shiro是如何清除過期session的(源碼版本shiro1.6)


shiro是如何清除過期session的(源碼版本shiro1.6)

由於項目中的shiro的緩存管理器替換為redis,故此處簡略追蹤記錄過期session的銷毀過程。

一、SecurityManager

安全管理器SecurityManager可以說是shiro最最重要的組件

  • 所有的安全交互都和它相關
  • 管理着所有的Subject
  • CacheManager交由它管理
  • Realm也交由它管理
  • SessionManager也由它管理

一、session的創建

session的創建的入口是SessionsSecurityManager#start,它進而調用SessionManager的start方法

public Session start(SessionContext context) throws AuthorizationException {
       return this.sessionManager.start(context);
  }

AbstractNativeSessionManager#start創建session方法如下

public Session start(SessionContext context) {
    // 創建session:SimpleSession
    Session session = createSession(context);
    //設置session的timeout時間:默認30分鍾
    applyGlobalSessionTimeout(session);
    //根據sessionId 生成cookie存入到request response中
    onStart(session, context);
    //通知session監聽器
    notifyStart(session);
    //Don't expose the EIS-tier Session object to the client-tier:
    //把SimpleSession包裝為DelegatingSession
    return createExposedSession(session, context);
}

AbstractValidatingSessionManager#createSession

protected Session createSession(SessionContext context) throws AuthorizationException {
        enableSessionValidationIfNecessary();
        return doCreateSession(context);
    }
doCreateSession方法簡要說明
  1. 通過SimpleSessionFactory創建session實例:SimpleSession
  2. 通過SessionDAO緩存session;
    1. 默認MemorySessionDAO存儲在內存中的ConcurrentMap
    2. 根據配置的緩存管理器,緩存session,我們的項目使用的是EnterpriseCacheSessionDAO,並為此dao配置了自定義的cacheManager(基於redis的)

二 session的定時清除

在上文創建session的時候首選執行的是方法是enableSessionValidationIfNecessary,它開啟了一個定時器

AbstractValidatingSessionManager#enableSessionValidationIfNecessary方法說明

private void enableSessionValidationIfNecessary() {
    //獲取session校驗調度器
    SessionValidationScheduler scheduler = getSessionValidationScheduler();
    if (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) {
        //啟用session檢驗
        enableSessionValidation();
    }
}

在追蹤定時器源碼之前,我們先看一下SimpleSession的基本屬性有哪些

SimpleSession部分源碼查看

public class SimpleSession implements ValidatingSession, Serializable {
    //.....
    //session Id
    private transient Serializable id;
    //session的創建時間
    private transient Date startTimestamp;
    //session的停止時間
    private transient Date stopTimestamp;
    //session的最近一次訪問時間,初始值是startTimestamp
    private transient Date lastAccessTime;
    //session的有效時長,默認30分鍾
    private transient long timeout;
    //session是否到期
    private transient boolean expired;
    //主機
    private transient String host;
    //存放的屬性  session.setAttributes存入的屬性
    private transient Map<Object, Object> attributes;
    
    //根據最后訪問時間和有效時間判斷 是否過期▲
    protected boolean isTimedOut() {
        //代碼略
    }
    //更新最后訪問時間 ▲
    public void touch() {
        this.lastAccessTime = new Date();
    }
    
    //session檢驗▲
    public void validate() throws InvalidSessionException {
        //check for stopped: stopTimestamp不為空 ▲
        if (isStopped()) {
            //timestamp is set, so the session is considered stopped:
            throw new StoppedSessionException(msg);
        }
        //check for expiration  過期了 ▲
        if (isTimedOut()) {
            //設置 expired  = true
            expire();
            //throw an exception explaining details of why it expired:
  
            throw new ExpiredSessionException(msg);
        }
    }
}

了解了SimpleSession的基本結構我,我們繼續查看session檢驗定時器

上文的enableSessionValidation方法進入到的是ExecutorServiceSessionValidationScheduler的enableSessionValidation方法

ExecutorServiceSessionValidationScheduler#enableSessionValidation

  • 默認每隔一小時執行一次run方法
public void enableSessionValidation() {    
        // 創建ScheduledExecutorService
        this.service = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {  
	       //.....
	        }  
        });    
            // 初始化service interval時長之后開始執行this的run方法,每隔interval執行一次;
        this.service.scheduleAtFixedRate(this, interval, interval, TimeUnit.MILLISECONDS);
    }
    this.enabled = true;
}

ExecutorServiceSessionValidationScheduler#run

public void run() {
       //....
       this.sessionManager.validateSessions();
       //....
    }

  • 進入AbstractValidatingSessionManager的validateSessions方法

AbstractValidatingSessionManager的validateSessions

public void validateSessions() {
    //....
	//獲取sessionDao中的全部session
    Collection<Session> activeSessions = getActiveSessions();
	//分別校驗每個session	
    for (Session s : activeSessions) {
       SessionKey key = new DefaultSessionKey(s.getId());
        //真正的校驗方法
       validate(s, key);               
    }
}

AbstractValidatingSessionManager#validate ▲▲▲

protected void validate(Session session, SessionKey key) throws InvalidSessionException {
        try {
            doValidate(session);
        } catch (ExpiredSessionException ese) {
            //從sessionDao中刪除過期的session
            onExpiration(session, ese, key);
            throw ese;
        } catch (InvalidSessionException ise) {
            //從sessionDao中刪除不合法的session
            onInvalidation(session, ise, key);
            throw ise;
        }
    }
  1. doValidate方法 調用上文的SimpleSession中的validate進行校驗,它會在過期以及已經停止的情況下拋出異常

    if (session instanceof ValidatingSession) {
           ((ValidatingSession) session).validate();
        } else {     
            throw new IllegalStateException(msg);
        }
    
  2. onExpiration方法從sessionDao中刪除session▲▲▲

    protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
            onExpiration(s);
            notifyExpiration(s);
            afterExpired(s);
    }
    

    afterExpired調用的是DefaultSessionManager的afterExpired方法

DefaultSessionManager#afterExpired:通過SessionDao中刪除session
  • 或者是從內存中直接刪除session
  • 或者調用緩存管理器的remove方法
protected void afterExpired(Session session) {
    if (isDeleteInvalidSessions()) {
        delete(session);
    }
 }

其他-登出時時候如何刪除session的

  1. DelegatingSubject#logout →
  2. DefaultSecurityManager#logout →
    • stopSession(subject);即調用SimpleSession的stop方法

其他-session最后操作時間如何更新

  • 每次進入ShiroFilter都如自動調用
  • ShiroFilter 的父類AbstractShiroFilter在執行doFilterInternal方法 的時候會調用updateSessionLastAccessTime方法,在其內部執行了 session.touch();
  • AbstractShiroFilter的doFilterInternal調用時機在其父類OncePerRequestFilter中的doFilter方法內,它會調用doFilterInternal方法

其他-AbstractNativeSessionManager中的lookupSession中的session校驗

  • AbstractNativeSessionManager 對session的相關操作(如屬性操作/設置過期時間/stop/touch等等等)均為調用lookupSession方法
  • 在lookupSession方法中調用doGetSession方法。
  • 調用的就是AbstractValidatingSessionManager 的validate方法,參見上文定時器作為入口時,對session的清除等處理

總結:

  • 了解shiro中最重要的對象securityManager是一個大管家,它管理着shiro生命周期的幾乎所有的關聯對象。

  • sessionManager的相關管理了session相關的所有操作,包括對session檢驗的定時器的定義,同時在session其他的操作的時候也會檢驗session的有效性

  • SimpleSession自身對檢驗


免責聲明!

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



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