1. 程式人生 > 實用技巧 >spring security 5 session管理

spring security 5 session管理

spring security 如何儲存我們的登入資訊。


根據官方文件我們可以知道通過登入驗證(AuthenticationProvider.authenticate(Authentication authentication)方法中驗證)後,會將一個驗證通過的例項Authentication放入安全上下文SecurityContextSecurityContext可從SecurityContextHolder中獲得。
Authentication資訊包括:

  • principal -驗證使用者,通常為UserDetails例項(實際生產中實現該介面,通過資料庫查詢該資訊)。
  • credentials -通常是密碼。在許多情況下,將在驗證使用者身份後清除此內容,以確保它不會洩漏。
  • authorities -許可權GrantedAuthority。 通常是角色或範圍。

驗證通過後,後續需要登入使用者資訊可直接從Authentication獲取。

spring security 如何記錄登入狀態

我們知道javaweb 通過jsession 會話id來確保同一個會話,同一個連線。在security中同樣通過jSessionId來記錄使用者登入,每次請求到達服務端,會通過ConcurrentSessionFilter過濾器驗證是否存在該session,不存在則不是登入狀態。驗證通過繼續執行FilterChain後續的過濾器。
ConcurrentSessionFilter

部分原始碼

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        HttpSession session = request.getSession(false);
        if (session != null) {
            SessionInformation info = this.sessionRegistry.getSessionInformation(session.getId());
            if (info != null) {
                //session過期做退出登入處理
                if (info.isExpired()) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Requested session ID " + request.getRequestedSessionId() + " has expired.");
                    }

                    this.doLogout(request, response);
                    this.sessionInformationExpiredStrategy.onExpiredSessionDetected(new SessionInformationExpiredEvent(info, request, response));
                    return;
                }
                //若該session存在,則重新整理它的最後請求時間
                this.sessionRegistry.refreshLastRequest(info.getSessionId());
            }
        }
        //若該session不存在,後續處理中會做未登入處理
        chain.doFilter(request, response);
    }

SessionManagementFilter部分原始碼

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        //判斷是否被該過濾器處理過
        if (request.getAttribute("__spring_security_session_mgmt_filter_applied") != null) {
            chain.doFilter(request, response);
        } else {
            request.setAttribute("__spring_security_session_mgmt_filter_applied", Boolean.TRUE);
            if (!this.securityContextRepository.containsContext(request)) {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                if (authentication != null && !this.trustResolver.isAnonymous(authentication)) {
                    try {
                        this.sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
                    } catch (SessionAuthenticationException var8) {
                        this.logger.debug("SessionAuthenticationStrategy rejected the authentication object", var8);
                        SecurityContextHolder.clearContext();
                        this.failureHandler.onAuthenticationFailure(request, response, var8);
                        return;
                    }

                    this.securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
                } else if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Requested session ID " + request.getRequestedSessionId() + " is invalid.");
                    }

                    if (this.invalidSessionStrategy != null) {
                        this.invalidSessionStrategy.onInvalidSessionDetected(request, response);
                        return;
                    }
                }
            }

            chain.doFilter(request, response);
        }
    }
退出登入或刪除cookie後的請求security如何處理
  • 請求中攜帶 jSessionId時只能請求公共資源,無法訪問私有資源。(security 定義)
    WebSecurityConfigurerAdapter繼承類中定義
@Override
	public void configure(WebSecurity web) throws Exception {
                //指定多個公共資源,無需登入即可訪問
		web.ignoring().antMatchers("/login.html", "/page/login/**");
	}
  • 退出登入後的請求會繼續驗證session是否存在,不存在則重新登入。