檢驗使用者單點登入方案解決
早期的web基本用語文件的處理,既然是瀏覽作為伺服器不需要判斷現在是誰在瀏覽。有請求直接響應就可以了,後來因為互動式應用的興起(線上購物,微博),伺服器有了一個新的要求:管理會話。也就是必須記住是哪個人往購物車放了東西,哪個人發了新的微博。因為http請求是無狀態的,所以想出來的辦法就是在第一次請求伺服器的時候生成一個隨機的字串 也就是所謂的session id。伺服器和客戶端分別保管一個,在客戶端請求的時候帶上這個session id,這樣伺服器就能知道誰是誰了。但是這樣又衍生了很多問題,首先就是客戶端只用保管自己的session id,但是服務端要管理所有人的id,當用戶過多的時候會導致伺服器壓力太大。除此之外,隨著分散式系統越來越流行,不同的伺服器處理不同的模組需求,客戶可能在伺服器A上登入,但是如果下一次的請求被轉發到伺服器B那就沒辦法了。如果讓客戶的請求一直一直黏在一個機器上,這個機器掛了那麼還得轉到其他機器上去。所以檢驗使用者是否登入的辦法說到底就是“驗證”。
先說一下session id的實現方式
使用主流的Spring MVC框架的攔截器可以實現此方法(用於在某個方法被訪問之前進行攔截,然後在方法執行之前或之後加入某些操作,是aop的一種實現)
手寫一個配置類,實現HandlerInterceptor介面
//攔截器 public class RequestInterceptor implements HandlerInterceptor { //方法結束後執行 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throwsException { System.out.println("方法結束"); } //進入方法前執行 返回值為true則執行方法 為false則不執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果請求的是user/login方法則直接放行
if("/user/login".equals(request.getServletPath())){
return true;
}
return request.getSession().getAttribute("user") != null; } }
需要注意上述程式碼需要在WebMvcConfigurer的實現類裡重寫addInterceptor方法裡新增此自定義攔截器
//註冊攔截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestInterceptor()); }
通過上述程式碼可以發現,在進入方法前需要檢查session裡有沒有"user",而且對於user/login是直接放行的,所以可以通過user/login來放入使用者資訊
寫一個controller處理此方法
//組合式註解 Responsbody+Controller //如果不需要返回值到客戶端 可以只用@Controller @RestController public class UserModuleController { //url對映 @RequestMapping("/user/login") public String doLogin(@RequestParam("username")String name, HttpServletRequest request){ //做一下資料校驗 if("admin".equals(name)){ request.getSession().setAttribute("user",name); //建議不要使用魔法值,此處可以寫一個常量類用靜態變數匯入 String retuenMessage="登入成功"; return retuenMessage; } String returnMessage="登入失敗,請檢查你的賬號"; return returnMessage; } }
執行專案 使用postman測試
token機制: 既然檢驗使用者登陸的核心是驗證,那麼有沒有可能資訊存放在客戶端,使用者每次請求的時候帶上這個資訊令牌來讓後端來驗證。
實現:和session差不多,使用者登陸成功之後,服務端根據演算法 將使用者的資訊和金鑰加密成字串再將該字串相應給使用者,此後使用者每次請求的時候在響應頭裡加入此token。攔截器通過request.getHeader("token")來獲取該字串並解密來判斷該請求是哪個使用者傳送的