spring security 5 session管理
阿新 • • 發佈:2020-12-17
spring security 如何儲存我們的登入資訊。
根據官方文件我們可以知道通過登入驗證(AuthenticationProvider.authenticate(Authentication authentication)方法中驗證)後,會將一個驗證通過的例項Authentication
放入安全上下文SecurityContext
,SecurityContext
可從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是否存在,不存在則重新登入。