一、基於session的身份認證方案
1.方案圖示
2.比較通用的鑒權流程實現如下:
在整個流程中有兩個攔截器。
第一個攔截器
AuthInteceptor是為了每一次的請求的時候都先去session中取user對象,如果session中有,就放user對象到threadlocal中。這是為了業務處理的時候能直接獲取用戶對象。
第二個攔截器
AuthActionInteceptor是先看頁面是否需要登錄,如果不需要登錄,則直接進行業務邏輯處理;如果需要登錄,則判斷是否已經登錄(UserContext.getUser()是否為空),沒有登錄則重定向到登錄頁面,登錄后是會把用戶信息放到session當中的 。

@Component public class AuthInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Map<String, String[]> map = request.getParameterMap(); map.forEach((k,v) -> { if (k.equals("errorMsg") || k.equals("successMsg") || k.equals("target")) { request.setAttribute(k, Joiner.on(",").join(v)); } }); String reqUri = request.getRequestURI(); if (reqUri.startsWith("/static") || reqUri.startsWith("/error") ) { return true; } HttpSession session = request.getSession(true);//參數為true,沒有session則創建新的 User user = (User)session.getAttribute(CommonConstants.USER_ATTRIBUTE); if (user != null) { UserContext.setUser(user); } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserContext.remove(); } }

@Component public class AuthActionInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { User user = UserContext.getUser(); if (user == null) { String msg = URLEncoder.encode("請先登錄","utf-8"); String target = URLEncoder.encode(request.getRequestURL().toString(),"utf-8"); if ("GET".equalsIgnoreCase(request.getMethod())) { response.sendRedirect("/accounts/signin?errorMsg=" + msg + "&target="+target); return false;//修復bug,未登錄要返回false }else { response.sendRedirect("/accounts/signin?errorMsg="+msg); return false;//修復bug,未登錄要返回false } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }

@Configuration public class WebMvcConf extends WebMvcConfigurerAdapter { @Autowired private AuthActionInterceptor authActionInterceptor; @Autowired private AuthInterceptor authInterceptor; @Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(authInterceptor).addPathPatterns("/**").excludePathPatterns("/static"); registry .addInterceptor(authActionInterceptor).addPathPatterns("/house/toAdd") .addPathPatterns("/accounts/profile").addPathPatterns("/accounts/profileSubmit") .addPathPatterns("/house/bookmarked").addPathPatterns("/house/del") .addPathPatterns("/house/ownlist").addPathPatterns("/house/add") .addPathPatterns("/house/toAdd").addPathPatterns("/agency/agentMsg") .addPathPatterns("/comment/leaveComment").addPathPatterns("/comment/leaveBlogComment"); super.addInterceptors(registry); } }
為什么要分成兩個攔截器呢?
第一個攔截器是為了攔截除靜態資源以外的任何資源,並且從session中取user放到ThreadLocal中,至於為什么要這么做,是可以在后面的業務處理邏輯中都可以方便使用到它,具體請參考
ThreadLocal管理session
第二個攔截器才是對於需要進行訪問控制的資源進行判斷處理。
最后業務邏輯處理完后,都需要將user從threadlocal中移除,以免影響以后的請求,因為我們的請求線程是處在線程池中的,每個線程在下一個請求中都可以復用。
3.缺點
1).sessio需要存在服務器內存中,這樣就不能跨實例共享。當下一次請求被分發到另一個實例的時候,就會造成重新登錄。
2).在高並發情況下,session放在內存中受限於內存的大小
3).session依賴於瀏覽器的cookie機制,對於移動客戶端就很難支持。移動端使用token。
二、基於token的身份認證方案
優點:
1.token方案保證了服務的無狀態,所有的信息都是存在分布式緩存中。基於分布式存儲,這樣可以水平擴展來支持高並發。
2.不依賴與cookie機制,可以通過客戶端約定的協議來傳輸token,瀏覽器可以存在cookie中,手機端可以放在內存或者本地文件中,代價是增加了外部存儲依賴以及在代碼方面要復雜。
注:
Session 是一種HTTP存儲機制,目的是為無狀態的HTTP提供的持久機制。所謂 Session 認證只是簡單的把 User 信息存儲到 Session 里,因為 SID 的不可預測性,暫且認為是安全的。這是一種認證手段。
Token,指的是 OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對用戶,授權是針對 App 。其目的是讓 某App 有權利訪問 某用戶 的信息。
Token,指的是 OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對用戶,授權是針對 App 。其目的是讓 某App 有權利訪問 某用戶 的信息。
這里的 Token 是唯一的。不可以轉移到其它 App 上,也不可以轉到其它 用戶 上。
下一篇將詳細介紹基於JWT的身份認證方案