Shiro自身維護了一套session管理組件,它可以獨立使用,並不單純依賴WEB/Servlet/EJB容器等環境,使得它的session可以任何應用中使用。 2-Session)主要介紹在quickstart例子中從獲取Subject後,由初始化獲取Session並寫入讀出session參數的完 ...
Shiro自身維護了一套session管理組件,它可以獨立使用,並不單純依賴WEB/Servlet/EJB容器等環境,使得它的session可以任何應用中使用。
2-Session)主要介紹在quickstart例子中從獲取Subject後,由初始化獲取Session並寫入讀出session參數的完整過程。
同樣,本篇本文使用的是shiro 1.3.2版本,配合源碼最佳~
Shiro自身提供了SessionManager的三種實現來支持不同的模式
DefaultSessionManager:Shiro自身維護的session,可在普通應用環境使用
DefaultWebSessionManager:獨立提供在shiro-web包中,繼承SessionManager,並額外支持WEB相關方法
ServletContainerSessionManager:使用Servlet容器提供Session管理,提供少量額外方法
在samples-quickstart例子中使用到的是DefaultSessionManager。
篇1(Shiro官方快速入門10min例子源碼解析框架1-初始化)中,1.2節DefaultSecurityManager是DefaultSessionManager的子類,在初始化DefaultSecurityManager時一同初始化DefaultSessionManager
在獲取到Subject後,繼續看samples-quickstart的代碼如何獲取和設置Session
Subject currentUser = SecurityUtils.getSubject();
2.1下一步是獲取Session,調用Subject的getSession方法
Session session = currentUser.getSession();
DelegatingSubject中,getSession()若無參數,則調用getSession(true),如果不需要Shiro 的Session功能可以調用getSession(false),
public Session getSession() { return getSession(true); }
調用DelegatingSubject.getSession(true),前半部分是日誌,及isSessionCreationEnabled()判斷(預設為ture)
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; }
主要在後半部分sessionContext、session獲取,及decorate過程
2.1.1獲取預設空白sessonContext,其為map的子類,
2.1.2構建session將sessionContext綁定到其中
2.1.3包裝session
2.1.2調用SessionsSecurityManager.start 其中sessionManager是DefaultSessionManager的實例
public Session start(SessionContext context) throws AuthorizationException { return this.sessionManager.start(context); }
其調用父類AbstractNativeSessionManager中的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); }
2.1.2.1構建Session
2.1.2.2設置session過期時間
2.1.2.3onStart操作,作為session監聽器點(本例無監聽器
2.1.2.4調用監聽器onStart(本例無監聽器
2.1.2.5創建
2.1.2.1繼而AbstractNativeSessionManager.createSession()調用AbstractValidatingSessionManager.createSession() 啟用session的驗證功能,
protected Session createSession(SessionContext context) throws AuthorizationException { enableSessionValidationIfNecessary(); return doCreateSession(context); }
繼續調用DefaultSessionManager.doCreateSession(),DefaultSessionManager調用newSessionInstance,
protected Session doCreateSession(SessionContext context) { Session s = newSessionInstance(context); if (log.isTraceEnabled()) { log.trace("Creating session for host {}", s.getHost()); } create(s); return s; }
獲得SimpleSessionFactory工廠後構建調用SimpleSessionFactory.createSession()
此時session中只有時間戳、session失效時間等信息
繼而調用DefaultSessionManager.create() 持久化session(由於例子中未設置外部DAO則使用的是MemorySessionDAO實例
protected void create(Session session) { if (log.isDebugEnabled()) { log.debug("Creating new EIS record for new session instance [" + session + "]"); } sessionDAO.create(session); }
這一步中會 為session生成一個UUID作為sessionID,並保存到session中,調用storeSession()將session 及其ID保存在MemorySessionDAO實例中的一個ConcurrentMap sessions中
protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); storeSession(sessionId, session); return sessionId; }
最後成功返回session
2.1.2.2依據全局session過期時間設置session並更新到sessionDAO
protected void applyGlobalSessionTimeout(Session session) { session.setTimeout(getGlobalSessionTimeout()); onChange(session); }
2.1.2.5
將SimpleSession轉化為外部可用的DelegatingSession
protected Session createExposedSession(Session session, SessionContext context) { return new DelegatingSession(this, new DefaultSessionKey(session.getId())); }
2.1.3將session包裝成統一的StoppingAwareProxiedSession,後續通過委托操作session內的方法
protected Session decorate(Session session) { if (session == null) { throw new IllegalArgumentException("session cannot be null"); } return new StoppingAwareProxiedSession(session, this); }
最後各處返回得到session
2.2在session中插入值
session.setAttribute("someKey", "aValue");
調用StoppingAwareProxiedSession父類方法ProxiedSession.setAttribute(),其中
public void setAttribute(Object key, Object value) throws InvalidSessionException { delegate.setAttribute(key, value); }
繼而調用DelegatingSession.setAttribute(),其中調用並調用AbstractNativeSessionManager.setAttribute(),參數sessionKey為當前DelegatingSession的sessionKey
public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException { if (value == null) { removeAttribute(sessionKey, attributeKey); } else { Session s = lookupRequiredSession(sessionKey); s.setAttribute(attributeKey, value); onChange(s); } }
2.2.1判斷來值是否為空
2.2.2.1
lookupRequiredSession(sessionKey)經過一系列過程,獲得sessionId,依據sessionId由sessionDAO從DAO中獲取simplesession實例
2.2.2.2空則刪除對應的session參數
2.2.3獲得的session設置參數
2.2.4sessionDAO中更新session
2.2在session中查找值
String value = (String) session.getAttribute("someKey");
調用StoppingAwareProxiedSession父類方法ProxiedSession.getAttribute(),
public Object getAttribute(Object key) throws InvalidSessionException { return delegate.getAttribute(key); }
與setAttribute()類似,從DAO中依據由sessionKey得到的sessionID獲得SimpleSession的實例,再調用其getAttribute方法獲得參數
public Object getAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException { return lookupRequiredSession(sessionKey).getAttribute(attributeKey); }
至此一個簡單的Session獲取及參數寫入讀取便完成了
參考:
http://shiro.apache.org/10-minute-tutorial.html
http://shiro.apache.org/session-management.html
http://www.apache.org/dyn/closer.cgi/shiro/1.3.2/shiro-root-1.3.2-source-release.zip
轉載請註明作者及來源:https://www.cnblogs.com/codflow/