日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

shiro登陆流程源码详解

發(fā)布時間:2025/7/14 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 shiro登陆流程源码详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

抽取了shiro最基本的登陸流程(web登陸是基于這層開發(fā)的)。
詳解源碼

創(chuàng)建一個AuthenticationToken進(jìn)行登錄。

SecurityUtils.getSecurityManager().login(null,authenticationToken); 復(fù)制代碼

登陸主流程

public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {AuthenticationInfo info;try {/*** 取獲校驗token的信息* 如果有返回就認(rèn)為登陸成功* 拋出任何AuthenticationException子類錯誤 就認(rèn)為登陸失敗*/info = authenticate(token);} catch (AuthenticationException ae) {throw ae;}/*** 走到這里* 證明已經(jīng)登陸成功* * 下一步就是創(chuàng)建Subject*/Subject loggedIn = createSubject(token, info, subject);return loggedIn; } 復(fù)制代碼

登陸身份校驗

public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {/*** 使用登陸器去登陸* 默認(rèn)使用ModularRealmAuthenticator*/return this.authenticator.authenticate(token); } 復(fù)制代碼protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {assertRealmsConfigured();Collection<Realm> realms = getRealms();if (realms.size() == 1) {return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);} else {//只演示單realm的情況 // return doMultiRealmAuthentication(realms, authenticationToken);return null;} } 復(fù)制代碼/*** 只有一個realm的情況下使用* @param realm* @param token* @return*/protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {/*** 先判斷這個realm是否可以校驗這個token* 這個方法需要我們在實現(xiàn)自己的realm時重寫*/if (!realm.supports(token)) {String msg = "Realm [" + realm + "] does not support authentication token [" +token + "]. Please ensure that the appropriate Realm implementation is " +"configured correctly or that the realm accepts AuthenticationTokens of this type.";throw new UnsupportedTokenException(msg);}/*** 從我們自己的realm中獲取校驗后的登陸信息*/AuthenticationInfo info = realm.getAuthenticationInfo(token);if (info == null) {String msg = "Realm [" + realm + "] was unable to find account data for the " +"submitted AuthenticationToken [" + token + "].";throw new UnknownAccountException(msg);}return info; } 復(fù)制代碼

創(chuàng)建Subject

/*** 登陸成功后創(chuàng)建Subject* 如果已經(jīng)有subject* 則把現(xiàn)在的認(rèn)證信息與原來的Subject綁定* 如果沒有Subject 則創(chuàng)建一個 并執(zhí)行綁定操作* @param token* @param info* @param existing* @return*/ protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {SubjectContext context = createSubjectContext();context.setAuthenticated(true); //增加了登陸成功的標(biāo)志/*** 同時保存了登陸的token和realm認(rèn)證后返回的信息*/context.setAuthenticationToken(token); context.setAuthenticationInfo(info);if (existing != null) {context.setSubject(existing);}return createSubject(context); } 復(fù)制代碼public Subject createSubject(SubjectContext subjectContext) {//復(fù)制了一遍subjectContextSubjectContext context = copy(subjectContext);//確保存在SecurityManagercontext = ensureSecurityManager(context);//解析Sessioncontext = resolveSession(context);Subject subject = doCreateSubject(context);/*** 保存subject* web情況下 會保存在session中*/save(subject);return subject; } 復(fù)制代碼protected Subject doCreateSubject(SubjectContext context) {//使用Subject工廠統(tǒng)一創(chuàng)建Subjectreturn getSubjectFactory().createSubject(context); } 復(fù)制代碼public Subject createSubject(SubjectContext context) {SecurityManager securityManager = context.resolveSecurityManager();//解析sessionSession session = context.resolveSession();/*** session是否自動創(chuàng)建標(biāo)記* ,沒開啟 會報錯 @DelegatingSubject$getSession(boolean create)*/boolean sessionCreationEnabled = context.isSessionCreationEnabled();//realm中返回的用戶憑證信息PrincipalCollection principals = context.resolvePrincipals();boolean authenticated = context.resolveAuthenticated();//創(chuàng)建return new DelegatingSubject(principals, authenticated, session, sessionCreationEnabled, securityManager); } 復(fù)制代碼

保存subject

/*** 具體保存邏輯* 由subjectDAO的實現(xiàn)類完成* @param subject*/ protected void save(Subject subject) {this.subjectDAO.save(subject); } 復(fù)制代碼/*** 默認(rèn)的實現(xiàn)方式是把subject保存到session中* @param subject* @return*/ public Subject save(Subject subject) {if (isSessionStorageEnabled(subject)) {saveToSession(subject);} else {log.trace("Session storage of subject state for Subject [{}] has been disabled: identity and " +"authentication state are expected to be initialized on every request or invocation.", subject);}return subject; } 復(fù)制代碼/*** 保存登陸的信息和登陸的狀態(tài)* @param subject*/ protected void saveToSession(Subject subject) {mergePrincipals(subject);mergeAuthenticationState(subject); } 復(fù)制代碼protected void mergePrincipals(Subject subject) {PrincipalCollection currentPrincipals = null;if (currentPrincipals == null || currentPrincipals.isEmpty()) {currentPrincipals = subject.getPrincipals();}Session session = subject.getSession(false);/*** 如果有Session* 則把變動的PrincipalCollection保存進(jìn)去*/if (session == null) {if (!isEmpty(currentPrincipals)) {session = subject.getSession();session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, currentPrincipals);}} else {PrincipalCollection existingPrincipals =(PrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);if (isEmpty(currentPrincipals)) {if (!isEmpty(existingPrincipals)) {session.removeAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);}} else {//只有修改過了的,才會被保存if (!currentPrincipals.equals(existingPrincipals)) {session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, currentPrincipals);}}} } 復(fù)制代碼/*** 刷新session中的登陸標(biāo)記* @param subject*/ protected void mergeAuthenticationState(Subject subject) {Session session = subject.getSession(false);if (session == null) {if (subject.isAuthenticated()) {/*** 如果登陸成功,并且第一次訪問Session* 則會去創(chuàng)建也給新的*/session = subject.getSession();session.setAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY, Boolean.TRUE);}} else {/*** 如果有session* 則更新標(biāo)記*/Boolean existingAuthc = (Boolean) session.getAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY);if (subject.isAuthenticated()) {if (existingAuthc == null || !existingAuthc) {session.setAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY, Boolean.TRUE);}} else {if (existingAuthc != null) {session.removeAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY);}}} } 復(fù)制代碼

保存subject時,如何生成的session(如果開啟)

protected Session createSession(SessionContext context) throws AuthorizationException {return doCreateSession(context); } 復(fù)制代碼protected Session doCreateSession(SessionContext context) {/*** 使用工廠類創(chuàng)建session* 默認(rèn)SimpleSession*/Session s = newSessionInstance(context);create(s);return s; } 復(fù)制代碼public Session createSession(SessionContext initData) {/*** 這里生成sessionId 可以嗎?*/return new SimpleSession(); } 復(fù)制代碼

shiro默認(rèn)使用MemorySessionDAO

protected void create(Session session) {if (log.isDebugEnabled()) {log.debug("Creating new EIS record for new session instance [" + session + "]");}//最終交由sessionDAO生成sessionDAO.create(session); } 復(fù)制代碼protected Serializable doCreate(Session session) {/*** sessionId最終在SessionDAO中生成* 默認(rèn)使用java的uuid*/Serializable sessionId = generateSessionId(session);assignSessionId(session, sessionId);storeSession(sessionId, session);return sessionId; } 復(fù)制代碼

修改session時,shiro是如何同步到本地的(或者HttpSession)

/*** 如果沒有session* 則創(chuàng)建* @param create* @return*/ @Override 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()) { //沒開啟sessionCreationEnabled 會報錯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);}/*** 創(chuàng)建的是DefaultSessionContext* 默認(rèn)沒什么內(nèi)容*/SessionContext sessionContext = createSessionContext();/*** 最終交由securityManager來生成Session*/Session session = this.securityManager.start(sessionContext);/*** 最終讓用戶操作的多次包裝的Session*/this.session = decorate(session);}return this.session; } 復(fù)制代碼 public Session start(SessionContext context) {/**.* 創(chuàng)建了一個SimpleSession*/Session session = createSession(context);onStart(session, context);/*** 創(chuàng)建對外暴露的Session* 其實就是代理了一下** 主要為了讓session在普通的操作下完成更多的功能*/return createExposedSession(session, context); } 復(fù)制代碼protected Session createExposedSession(Session session, SessionContext context) {//代理Sessionreturn new DelegatingSession(this, new DefaultSessionKey(session.getId())); } 復(fù)制代碼/*** 代理的session* 他會把對所有對session的操作* 提交給sessionManager去處理* @Author: lilingyan* @Date 2019/6/3 13:37*/ public class DelegatingSession implements Session {private final SessionKey key;private final transient NativeSessionManager sessionManager;@Overridepublic void setAttribute(Object attributeKey, Object value) throws InvalidSessionException {if (value == null) {removeAttribute(attributeKey);} else {//被代理了sessionManager.setAttribute(this.key, attributeKey, value);}}... 復(fù)制代碼//在SessionManager中代理的處理方法 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);} } ... 復(fù)制代碼protected void onChange(Session session) {//最終任何修改都會被傳遞到sessionDAOsessionDAO.update(session); } 復(fù)制代碼

轉(zhuǎn)載于:https://juejin.im/post/5cf4d92951882521bf340aa0

總結(jié)

以上是生活随笔為你收集整理的shiro登陆流程源码详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。