Spring Security Session並發控制原理解析


當使用spring security 的標簽,如下,其中<sec:session-management>對應的SessionManagementFilter。從名字可以看出,這是一個管理Session的過濾器。這個過濾器會攔截每一個請求。然后判斷用戶有沒有認證過。如果已經認證過,則執行Session認證策略。session 認證策略可配置。我們來看看這個過濾器的源代碼,具體邏輯就直接在源碼上標注。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

if (request.getAttribute(FILTER_APPLIED) != null) { chain.doFilter(request, response); return; } request.setAttribute(FILTER_APPLIED, Boolean.TRUE); if (!securityContextRepository.containsContext(request)) {// 第一次訪問,直接放行 Authentication authentication = SecurityContextHolder.getContext() .getAuthentication();//獲取認證對象 if (authentication != null && !trustResolver.isAnonymous(authentication)) {//用戶已經認證過 // The user has been authenticated during the current request, so call the // session strategy try { sessionAuthenticationStrategy.onAuthentication(authentication, request, response); //這里是session管理的關鍵,具體邏輯請看Session認證策略 } catch (SessionAuthenticationException e) { // The session strategy can reject the authentication logger.debug( "SessionAuthenticationStrategy rejected the authentication object", e); SecurityContextHolder.clearContext(); failureHandler.onAuthenticationFailure(request, response, e); return; } // Eagerly save the security context to make it available for any possible // re-entrant // requests which may occur before the current request completes. // SEC-1396. securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response); } else { // No security context or authentication present. Check for a session // timeout if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) { if (logger.isDebugEnabled()) { logger.debug("Requested session ID " + request.getRequestedSessionId() + " is invalid."); } if (invalidSessionStrategy != null) { invalidSessionStrategy .onInvalidSessionDetected(request, response); return; } } } } chain.doFilter(request, response); }

 

CompositeSessionAuthenticationStrategy.java:

public void onAuthentication(Authentication authentication,
            HttpServletRequest request, HttpServletResponse response)
            throws SessionAuthenticationException {
        for (SessionAuthenticationStrategy delegate : delegateStrategies) {
            if (logger.isDebugEnabled()) {
                logger.debug("Delegating to " + delegate);
            }
            delegate.onAuthentication(authentication, request, response);
        }
    }

ConcurrentSessionControlAuthenticationStrategy.java
/**
     * In addition to the steps from the superclass, the sessionRegistry will be updated
     * with the new session information.
     */
    public void onAuthentication(Authentication authentication,
            HttpServletRequest request, HttpServletResponse response) {

        final List<SessionInformation> sessions = sessionRegistry.getAllSessions(
                authentication.getPrincipal(), false); // 根據認證主體獲取session int sessionCount = sessions.size();
        int allowedSessions = getMaximumSessionsForThisUser(authentication);

        if (sessionCount < allowedSessions) {
            // They haven't got too many login sessions running at present
            return;
        }

        if (allowedSessions == -1) {
            // We permit unlimited logins
            return;
        }

        if (sessionCount == allowedSessions) {
            HttpSession session = request.getSession(false);

            if (session != null) {
                // Only permit it though if this request is associated with one of the
                // already registered sessions
                for (SessionInformation si : sessions) {
                    if (si.getSessionId().equals(session.getId())) {
                        return;
                    }
                }
            }
            // If the session is null, a new one will be created by the parent class,
            // exceeding the allowed number
        }

        allowableSessionsExceeded(sessions, allowedSessions, sessionRegistry);
    }
protected void allowableSessionsExceeded(List<SessionInformation> sessions,
int allowableSessions, SessionRegistry registry)
throws SessionAuthenticationException {
if (exceptionIfMaximumExceeded || (sessions == null)) {
throw new SessionAuthenticationException(messages.getMessage(
"ConcurrentSessionControlAuthenticationStrategy.exceededAllowed",
new Object[] { Integer.valueOf(allowableSessions) },
"Maximum sessions of {0} for this principal exceeded"));
}

// Determine least recently used session, and mark it for invalidation
SessionInformation leastRecentlyUsed = null;

for (SessionInformation session : sessions) {
if ((leastRecentlyUsed == null)
|| session.getLastRequest()
.before(leastRecentlyUsed.getLastRequest())) {
leastRecentlyUsed = session;
}
}

leastRecentlyUsed.expireNow();
}
 

 

 

<sec:http>
  <sec:session-management/>
</sec:http>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM