Shiro 關於校驗Session過期、有效性的設計概念


核心行為

開啟Session校驗調度任務、校驗所有的session、具體的Session自我校驗、關閉Session校驗調度任務

核心類

ValidatingSessionManager、SessionValidationScheduler、ValidatingSession

ValidatingSessionManager的行為

public interface ValidatingSessionManager extends SessionManager {
    // 校驗所有的Session
    void validateSessions();
}

SessionValidationScheduler的行為

public interface SessionValidationScheduler {

    // Session校驗是否處於開啟狀態
    boolean isEnabled();

    // 開啟Session校驗 
    void enableSessionValidation();

    // 關閉Session校驗
    void disableSessionValidation();

}

ValidatingSession的行為

public interface ValidatingSession extends Session {

    // 校驗是否處於開啟狀態
    boolean isValid();

    // Session自我校驗
    void validate() throws InvalidSessionException;
}

校驗過程解析

ValidatingSessionManager開啟Session校驗調度任務 ==》 Session校驗調度任務中使用ValidatingSessionManager校驗所有的Session

==》 ValidatingSessionManager讓其子類獲得所有的Session(基礎Session) ==》 各個基礎Session自我校驗

ValidatingSessionManager開啟Session校驗調度任務

protected SessionValidationScheduler sessionValidationScheduler;

public void setSessionValidationScheduler(SessionValidationScheduler sessionValidationScheduler) {
    this.sessionValidationScheduler = sessionValidationScheduler;
}

protected synchronized void enableSessionValidation() {
    SessionValidationScheduler scheduler = getSessionValidationScheduler();
    if (scheduler == null) {
        scheduler = createSessionValidationScheduler();
        setSessionValidationScheduler(scheduler);
    }
    if (!scheduler.isEnabled()) {
        if (log.isInfoEnabled()) {
            log.info("Enabling session validation scheduler...");
        }
        // 開啟Session校驗調度任務
        scheduler.enableSessionValidation();
        afterSessionValidationEnabled();
    }
}

Session校驗調度任務中使用ValidatingSessionManager校驗所有的Session

public void run() {
    if (log.isDebugEnabled()) {
        log.debug("Executing session validation...");
    }
    long startTime = System.currentTimeMillis();
    // Session校驗任務調度時使用ValidatingSessionManager校驗所有的Session
    this.sessionManager.validateSessions();
    long stopTime = System.currentTimeMillis();
    if (log.isDebugEnabled()) {
        log.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds.");
    }
}

ValidatingSessionManager讓其子類獲得所有的Session(基礎Session)

protected abstract Collection<Session> getActiveSessions();

DefaultSessionManager具體執行獲得所有的基礎Session

protected Collection<Session> getActiveSessions() {
    Collection<Session> active = sessionDAO.getActiveSessions();
    return active != null ? active : Collections.<Session>emptySet();
}

各個基礎Session自我校驗

Collection<Session> activeSessions = getActiveSessions();
if (activeSessions != null && !activeSessions.isEmpty()) {
    for (Session s : activeSessions) {
        try {
            SessionKey key = new DefaultSessionKey(s.getId());
            // 各個基礎Session自我校驗
            validate(s, key);
        } catch (InvalidSessionException e) {
            if (log.isDebugEnabled()) {
                boolean expired = (e instanceof ExpiredSessionException);
                String msg = "Invalidated session with id [" + s.getId() + "]" +
                        (expired ? " (expired)" : " (stopped)");
                log.debug(msg);
            }
            invalidCount++;
        }
    }
}

protected void validate(Session session, SessionKey key) throws InvalidSessionException {
    try {
        doValidate(session);
    } catch (ExpiredSessionException ese) {
        onExpiration(session, ese, key);
        throw ese;
    } catch (InvalidSessionException ise) {
        onInvalidation(session, ise, key);
        throw ise;
    }
}

protected void doValidate(Session session) throws InvalidSessionException {
    if (session instanceof ValidatingSession) {
        // 基礎Session根據自己擁有的屬性值自我校驗
        ((ValidatingSession) session).validate();
    } else {
        String msg = "The " + getClass().getName() + " implementation only supports validating " +
                "Session implementations of the " + ValidatingSession.class.getName() + " interface.  " +
                "Please either implement this interface in your session implementation or override the " +
                AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";
        throw new IllegalStateException(msg);
    }
}

SimpleSession的自我校驗

public void validate() throws InvalidSessionException {
    // 校驗Session是否已經被停止使用了,如果Session已經被停止使用了則拋出異常
    if (isStopped()) {
        String msg = "Session with id [" + getId() + "] has been " +
                "explicitly stopped.  No further interaction under this session is " +
                "allowed.";
        throw new StoppedSessionException(msg);
    }

    // 校驗Session是否到了過期時間,如果Session已經到期了則拋出異常
    if (isTimedOut()) {
        expire();
        Date lastAccessTime = getLastAccessTime();
        long timeout = getTimeout();

        Serializable sessionId = getId();

        DateFormat df = DateFormat.getInstance();
        String msg = "Session with id [" + sessionId + "] has expired. " +
                "Last access time: " + df.format(lastAccessTime) +
                ".  Current time: " + df.format(new Date()) +
                ".  Session timeout is set to " + timeout / MILLIS_PER_SECOND + " seconds (" +
                timeout / MILLIS_PER_MINUTE + " minutes)";
        if (log.isTraceEnabled()) {
            log.trace(msg);
        }
        throw new ExpiredSessionException(msg);
    }
}

protected boolean isStopped() {
    return getStopTimestamp() != null;
}

protected boolean isTimedOut() {
    if (isExpired()) {
        return true;
    }
    long timeout = getTimeout();
    if (timeout >= 0l) {
        Date lastAccessTime = getLastAccessTime();
        if (lastAccessTime == null) {
            String msg = "session.lastAccessTime for session with id [" +
                    getId() + "] is null.  This value must be set at " +
                    "least once, preferably at least upon instantiation.  Please check the " +
                    getClass().getName() + " implementation and ensure " +
                    "this value will be set (perhaps in the constructor?)";
            throw new IllegalStateException(msg);
        }
        long expireTimeMillis = System.currentTimeMillis() - timeout;
        Date expireTime = new Date(expireTimeMillis);
        return lastAccessTime.before(expireTime);
    } else {
        if (log.isTraceEnabled()) {
            log.trace("No timeout for session with id [" + getId() +
                    "].  Session is not considered expired.");
        }
    }
    return false;
}

public boolean isExpired() {
    return expired;
}

protected void expire() {
    stop();
    this.expired = true;
}

public void stop() {
    if (this.stopTimestamp == null) {
        this.stopTimestamp = new Date();
    }
}

SimpleSession過期后自己無能為力,只能拋出異常交給AbstractValidatingSessionManager抓住異常進行特殊處理

protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
    log.trace("Session with id [{}] has expired.", s.getId());
    try {
        // 執行過期時的行為
        onExpiration(s);
        // 通知監聽器,Session過期之后做點什么
        notifyExpiration(s);
    } finally {
        // Session過期之后的行為,如在介質中刪除Session
        afterExpired(s);
    }
}

// 更新介質中的Session
protected void onExpiration(Session session) { onChange(session); } protected void afterExpired(Session session) { }

ValidatingSessionManager關閉Session校驗調度任務

protected synchronized void disableSessionValidation() {
    beforeSessionValidationDisabled();
    SessionValidationScheduler scheduler = getSessionValidationScheduler();
    if (scheduler != null) {
        try {
            // Session校驗任務調度器禁用校驗
            scheduler.disableSessionValidation();
            if (log.isInfoEnabled()) {
                log.info("Disabled session validation scheduler.");
            }
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                String msg = "Unable to disable SessionValidationScheduler.  Ignoring (shutting down)...";
                log.debug(msg, e);
            }
        }
        LifecycleUtils.destroy(scheduler);
        // 設置Session校驗任務調度器為 null
        setSessionValidationScheduler(null);
    }
}

Session任務調度器禁用Session校驗

public void disableSessionValidation() {
    if (this.service != null) {
        this.service.shutdownNow();
    }
    this.enabled = false;
}

 


免責聲明!

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



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