基於session和token的身份認證方案

1、基於session的身份認證方案html

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();
    }
    

}
View Code
@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 {

    }

}
View Code
@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);
    }

    
}
View Code
爲何要分紅兩個攔截器呢?
第一個攔截器是爲了攔截除靜態資源之外的任何資源,而且從session中取user放到ThreadLocal中,至於爲何要這麼作,是能夠在後面的業務處理邏輯中均可以方便使用到它,具體請參考 ThreadLocal管理session
第二個攔截器纔是對於須要進行訪問控制的資源進行判斷處理。
最後業務邏輯處理完後,都須要將user從threadlocal中移除,以避免影響之後的請求,由於咱們的請求線程是處在線程池中的,每一個線程在下一個請求中均可以複用。
 
3.缺點
  1).sessio須要存在服務器內存中,這樣就不能跨實例共享。當下一次請求被分發到另外一個實例的時候,就會形成從新登陸。
  2).在高併發狀況下,session放在內存中受限於內存的大小
  3).session依賴於瀏覽器的cookie機制,對於移動客戶端就很難支持。移動端使用token。

 

2、基於token的身份認證方案安全

優勢:服務器

  1.token方案保證了服務的無狀態,全部的信息都是存在分佈式緩存中。基於分佈式存儲,這樣能夠水平擴展來支持高併發。
  2.不依賴與cookie機制,能夠經過客戶端約定的協議來傳輸token,瀏覽器能夠存在cookie中,手機端能夠放在內存或者本地文件中,代價是增長了外部存儲依賴以及在代碼方面要複雜。
 
注:
Session 是一種HTTP存儲機制,目的是爲無狀態的HTTP提供的持久機制。所謂 Session 認證只是簡單的把 User 信息存儲到 Session 裏,由於 SID 的不可預測性,暫且認爲是安全的。這是一種認證手段。 
 Token,指的是 OAuth Token 或相似的機制的話,提供的是 認證 和 受權 ,認證是針對用戶,受權是針對 App 。其目的是讓 某App 有權利訪問 某用戶 的信息。
這裏的 Token 是惟一的。不能夠轉移到其它 App 上,也不能夠轉到其它 用戶 上。 
 
下一篇將詳細介紹基於JWT的身份認證方案
相關文章
相關標籤/搜索