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;
}

 

posted @ 2018-07-11 18:38  BINGJJFLY  阅读(8233)  评论(0编辑  收藏  举报