Shiro 4 sessionManager

来源:互联网 发布:时来天地皆同力 知乎 编辑:程序博客网 时间:2024/05/17 19:22

sessionManager接口

public interface SessionManager {  Session start(SessionContext context); Session getSession(SessionKey key) throws SessionException;}

实现继承

AbstractSessionManager定义了session过期时间globalSessionTimeout


AbstractNativeSessionManager定义了Collection<SessionListener> listeners,我们可以实现SessionListener接口,在触发这些事件时候,做些事情

而这些listener起作用的地方就是

protected void notifyStart(Session session) {        for (SessionListener listener : this.listeners) {            listener.onStart(session);        }    }    protected void notifyStop(Session session) {        Session forNotification = beforeInvalidNotification(session);        for (SessionListener listener : this.listeners) {            listener.onStop(forNotification);        }    }    protected void notifyExpiration(Session session) {        Session forNotification = beforeInvalidNotification(session);        for (SessionListener listener : this.listeners) {            listener.onExpiration(forNotification);        }    }

这个类中有对start和getSession的实现

start方法

public Session start(SessionContext context) {        Session session = createSession(context);        applyGlobalSessionTimeout(session);        onStart(session, context);        notifyStart(session);        //Don't expose the EIS-tier Session object to the client-tier:        return createExposedSession(session, context);    }protected abstract Session createSession(SessionContext context) throws AuthorizationException;protected void onStart(Session session, SessionContext context) {    }protected Session createExposedSession(Session session, SessionContext context) {        return new DelegatingSession(this, new DefaultSessionKey(session.getId()));    }

getSession方法

 public Session getSession(SessionKey key) throws SessionException {        Session session = lookupSession(key);        return session != null ? createExposedSession(session, key) : null;    }    private Session lookupSession(SessionKey key) throws SessionException {        if (key == null) {            throw new NullPointerException("SessionKey argument cannot be null.");        }        return doGetSession(key);    } protected abstract Session doGetSession(SessionKey key) throws InvalidSessionException;


AbstractValidatingSessionManager作用是对所有的session检测,字段sessionValidationSchedulerEnabled默认为true,是否检测

sessionValidationScheduler是具体去执行检测的类

createSession方法的实现

 protected Session createSession(SessionContext context) throws AuthorizationException {        enableSessionValidationIfNecessary();        return doCreateSession(context);    }    protected abstract Session doCreateSession(SessionContext initData) throws AuthorizationException;

doGetSession方法实现

@Override    protected final Session doGetSession(final SessionKey key) throws InvalidSessionException {        enableSessionValidationIfNecessary();        log.trace("Attempting to retrieve session with key {}", key);        Session s = retrieveSession(key);        if (s != null) {            validate(s, key);        }        return s;    }/**     * Looks up a session from the underlying data store based on the specified session key.     *     * @param key the session key to use to look up the target session.     * @return the session identified by {@code sessionId}.     * @throws UnknownSessionException if there is no session identified by {@code sessionId}.     */    protected abstract Session retrieveSession(SessionKey key) throws UnknownSessionException;

其中都用到了enableSessionValidationIfNecessary();这个方法就是去检测

private void enableSessionValidationIfNecessary() {        SessionValidationScheduler scheduler = getSessionValidationScheduler();        if (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) {            enableSessionValidation();        }    }protected synchronized void enableSessionValidation() {        SessionValidationScheduler scheduler = getSessionValidationScheduler();        if (scheduler == null) {            scheduler = createSessionValidationScheduler();            setSessionValidationScheduler(scheduler);            if (log.isInfoEnabled()) {                log.info("Enabling session validation scheduler...");            }            scheduler.enableSessionValidation();            afterSessionValidationEnabled();        }    }protected SessionValidationScheduler createSessionValidationScheduler() {        ExecutorServiceSessionValidationScheduler scheduler;        if (log.isDebugEnabled()) {            log.debug("No sessionValidationScheduler set.  Attempting to create default instance.");        }        scheduler = new ExecutorServiceSessionValidationScheduler(this);//默认的        scheduler.setInterval(getSessionValidationInterval());        if (log.isTraceEnabled()) {            log.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "].");        }        return scheduler;    } protected void afterSessionValidationEnabled() {    }

DefaultSessionManager是DefaultSecurityManager使用的默认实现,用于JavaSE环境,sessionFactory默认使用SimpleSessionFactory,

sessionDAO默认使用MemorySessionDAO

doCreateSession的实现

 protected Session doCreateSession(SessionContext context) {        Session s = newSessionInstance(context);        if (log.isTraceEnabled()) {            log.trace("Creating session for host {}", s.getHost());        }        create(s);        return s;    }    protected Session newSessionInstance(SessionContext context) {        return getSessionFactory().createSession(context);    } protected void create(Session session) {        if (log.isDebugEnabled()) {            log.debug("Creating new EIS record for new session instance [" + session + "]");        }        sessionDAO.create(session);    }

retrieveSession的实现

 protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {        Serializable sessionId = getSessionId(sessionKey);        if (sessionId == null) {            log.debug("Unable to resolve session ID from SessionKey [{}].  Returning null to indicate a " +                    "session could not be found.", sessionKey);            return null;        }        Session s = retrieveSessionFromDataSource(sessionId);        if (s == null) {            //session ID was provided, meaning one is expected to be found, but we couldn't find one:            String msg = "Could not find session with ID [" + sessionId + "]";            throw new UnknownSessionException(msg);        }        return s;    }protected Serializable getSessionId(SessionKey sessionKey) {        return sessionKey.getSessionId();    }protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException {        return sessionDAO.readSession(sessionId);    }



DefaultWebSessionManager用于Web环境的实现,可以替代ServletContainerSessionManager,自己维护着会话

 public DefaultWebSessionManager() {        Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);        cookie.setHttpOnly(true); //more secure, protects against XSS attacks        this.sessionIdCookie = cookie;        this.sessionIdCookieEnabled = true;    }
重写AbstractNativeSessionManager的onStart方法

 /**     * Stores the Session's ID, usually as a Cookie, to associate with future requests.     *     * @param session the session that was just {@link #createSession created}.     */    @Override    protected void onStart(Session session, SessionContext context) {        super.onStart(session, context);        if (!WebUtils.isHttp(context)) {            log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " +                    "pair. No session ID cookie will be set.");            return;        }        HttpServletRequest request = WebUtils.getHttpRequest(context);        HttpServletResponse response = WebUtils.getHttpResponse(context);        if (isSessionIdCookieEnabled()) {            Serializable sessionId = session.getId();            storeSessionId(sessionId, request, response);        } else {            log.debug("Session ID cookie is disabled.  No cookie has been set for new session with id {}", session.getId());        }        request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);    } private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {        if (currentId == null) {            String msg = "sessionId cannot be null when persisting for subsequent requests.";            throw new IllegalArgumentException(msg);        }        Cookie template = getSessionIdCookie();        Cookie cookie = new SimpleCookie(template);        String idString = currentId.toString();        cookie.setValue(idString);        cookie.saveTo(request, response);        log.trace("Set session ID cookie for session with id {}", idString);    }

getSessionId方法重写

 @Override    public Serializable getSessionId(SessionKey key) {        Serializable id = super.getSessionId(key);        if (id == null && WebUtils.isWeb(key)) {            ServletRequest request = WebUtils.getRequest(key);            ServletResponse response = WebUtils.getResponse(key);            id = getSessionId(request, response);        }        return id;    }    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {        return getReferencedSessionId(request, response);    } private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {        String id = getSessionIdCookieValue(request, response); //从cookie读取        if (id != null) {            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,                    ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);//设置sessionid位置        } else {            //not in a cookie, or cookie is disabled - try the request URI as a fallback (i.e. due to URL rewriting):            //try the URI path segment parameters first:            id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);//从url截取            if (id == null) {                //not a URI path segment parameter, try the query parameters:                String name = getSessionIdName();                id = request.getParameter(name);//从request的参数取                if (id == null) {                    //try lowercase:                    id = request.getParameter(name.toLowerCase());                }            }            if (id != null) {                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,                        ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);            }        }        if (id != null) {            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);            //automatically mark it valid here.  If it is invalid, the            //onUnknownSession method below will be invoked and we'll remove the attribute at that time.            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);        }        return id;    }

重写了AbstractNativeSessionManager的createExposedSession,将DelegatingSession的key换成WebSessionKey

  protected Session createExposedSession(Session session, SessionContext context) {        if (!WebUtils.isWeb(context)) {            return super.createExposedSession(session, context);        }        ServletRequest request = WebUtils.getRequest(context);        ServletResponse response = WebUtils.getResponse(context);        SessionKey key = new WebSessionKey(session.getId(), request, response);        return new DelegatingSession(this, key);    }


ServletContainerSessionManager implements WebSessionManager  extends SessionManager

DefaultWebSecurityManager使用的默认实现,用于Web环境,其直接使用Servlet容器的会话

public class ServletContainerSessionManager implements WebSessionManager {    //TODO - complete JavaDoc    //TODO - read session timeout value from web.xml    public ServletContainerSessionManager() {    }    public Session start(SessionContext context) throws AuthorizationException {        return createSession(context);    }    public Session getSession(SessionKey key) throws SessionException {        if (!WebUtils.isHttp(key)) {            String msg = "SessionKey must be an HTTP compatible implementation.";            throw new IllegalArgumentException(msg);        }        HttpServletRequest request = WebUtils.getHttpRequest(key);        Session session = null;        HttpSession httpSession = request.getSession(false);        if (httpSession != null) {            session = createSession(httpSession, request.getRemoteHost());        }        return session;    }    private String getHost(SessionContext context) {        String host = context.getHost();        if (host == null) {            ServletRequest request = WebUtils.getRequest(context);            if (request != null) {                host = request.getRemoteHost();            }        }        return host;    }    /**     * @since 1.0     */    protected Session createSession(SessionContext sessionContext) throws AuthorizationException {        if (!WebUtils.isHttp(sessionContext)) {            String msg = "SessionContext must be an HTTP compatible implementation.";            throw new IllegalArgumentException(msg);        }        HttpServletRequest request = WebUtils.getHttpRequest(sessionContext);        HttpSession httpSession = request.getSession();        //SHIRO-240: DO NOT use the 'globalSessionTimeout' value here on the acquired session.        //see: https://issues.apache.org/jira/browse/SHIRO-240        String host = getHost(sessionContext);        return createSession(httpSession, host);    }    protected Session createSession(HttpSession httpSession, String host) {        return new HttpServletSession(httpSession, host);    }    /**     * This implementation always delegates to the servlet container for sessions, so this method returns     * {@code true} always.     *     * @return {@code true} always     * @since 1.2     */public boolean isServletContainerSessions() {return true;}}


SessionManager使用在SessionsSecurityManager

 private SessionManager sessionManager;    /**     * Default no-arg constructor, internally creates a suitable default {@link SessionManager SessionManager} delegate     * instance.     */    public SessionsSecurityManager() {        super();        this.sessionManager = new DefaultSessionManager();        applyCacheManagerToSessionManager();    }

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

Subject中取得session最终是有securityManager完成

  public Session getSession(boolean create) {        if (log.isTraceEnabled()) {            log.trace("attempting to get session; create = " + create +                    "; session is null = " + (this.session == null) +                    "; session has id = " + (this.session != null && session.getId() != null));        }        if (this.session == null && create) {            //added in 1.2:            if (!isSessionCreationEnabled()) {                String msg = "Session creation has been disabled for the current subject.  This exception indicates " +                        "that there is either a programming error (using a session when it should never be " +                        "used) or that Shiro's configuration needs to be adjusted to allow Sessions to be created " +                        "for the current Subject.  See the " + DisabledSessionException.class.getName() + " JavaDoc " +                        "for more.";                throw new DisabledSessionException(msg);            }            log.trace("Starting session for host {}", getHost());            SessionContext sessionContext = createSessionContext();            Session session = this.securityManager.start(sessionContext);            this.session = decorate(session);        }        return this.session;    }



0 0