Shiro使用和源码分析---5
来源:互联网 发布:串口助手软件下载 编辑:程序博客网 时间:2024/06/10 17:44
getSubject分析
上一章看完了DefaultWebSecurityManager的构造函数,首先来分析getSubject函数。getSubject定义在AccessControlFilter中。
getSubject
protected Subject getSubject(ServletRequest request, ServletResponse response) { return SecurityUtils.getSubject(); }
再看SecurityUtils的getSubject函数,
public static Subject getSubject() { Subject subject = ThreadContext.getSubject(); if (subject == null) { subject = (new Subject.Builder()).buildSubject(); ThreadContext.bind(subject); } return subject; }
ThreadContext相当于一个线程安全的类,ThreadContext的getSubject函数定义如下
public static Subject getSubject() { return (Subject) get(SUBJECT_KEY); }
这里的SUBJECT_KEY=ThreadContext.class.getName() + “_SUBJECT_KEY”;,其get函数定义在ThreadContext中,如下
public static Object get(Object key) { if (log.isTraceEnabled()) { String msg = "get() - in thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } Object value = getValue(key); if ((value != null) && log.isTraceEnabled()) { String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } return value; }
getValue函数定义在ThreadContext中,如下
private static Object getValue(Object key) { Map<Object, Object> perThreadResources = resources.get(); return perThreadResources != null ? perThreadResources.get(key) : null; }
这里假设是第一次访问该Subject,返回null。回到getSubject函数,这里就需要调用buildSubject函数,首先看Builder的构造函数,定义在Subject接口中,如下
public Builder(SecurityManager securityManager) { if (securityManager == null) { throw new NullPointerException("SecurityManager method argument cannot be null."); } this.securityManager = securityManager; this.subjectContext = newSubjectContextInstance(); if (this.subjectContext == null) { throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + "cannot be null."); } this.subjectContext.setSecurityManager(securityManager); }
该构造函数就是简单的调用了newSubjectContextInstance,定义在Subject接口中,如下
protected SubjectContext newSubjectContextInstance() { return new DefaultSubjectContext(); }
DefaultSubjectContext的构造函数没有什么内容。回到getSubject函数中,接下来看buildSubject,如下
public Subject buildSubject() { return this.securityManager.createSubject(this.subjectContext); }
这里的securityManager就是前面构造的DefaultWebSecurityManager啦,subjectContext=DefaultSubjectContext。
createSubject定义在DefaultSecurityManager中,
public Subject createSubject(SubjectContext subjectContext) { SubjectContext context = copy(subjectContext); context = ensureSecurityManager(context); context = resolveSession(context); context = resolvePrincipals(context); Subject subject = doCreateSubject(context); save(subject); return subject; }
下面一一分析这些函数。
copy
protected SubjectContext copy(SubjectContext subjectContext) { return new DefaultSubjectContext(subjectContext); }
DefaultSubjectContext的构造函数就是简单的将SubjectContext 赋值。
ensureSecurityManager
ensureSecurityManager定义在DefaultSecurityManager中,
protected SubjectContext ensureSecurityManager(SubjectContext context) { if (context.resolveSecurityManager() != null) { log.trace("Context already contains a SecurityManager instance. Returning."); return context; } log.trace("No SecurityManager found in context. Adding self reference."); context.setSecurityManager(this); return context; }
这里就是查看SubjectContext是否有SecurityManager,如果没有就进行设置。该context就是刚刚构造的DefaultSubjectContext,它的resolveSecurityManager如下
public SecurityManager resolveSecurityManager() { SecurityManager securityManager = getSecurityManager(); if (securityManager == null) { if (log.isDebugEnabled()) { log.debug("No SecurityManager available in subject context map. " + "Falling back to SecurityUtils.getSecurityManager() lookup."); } try { securityManager = SecurityUtils.getSecurityManager(); } catch (UnavailableSecurityManagerException e) { if (log.isDebugEnabled()) { log.debug("No SecurityManager available via SecurityUtils. Heuristics exhausted.", e); } } } return securityManager; }
这个函数首先从该SubjectContext里取出SecurityManager,如果没有,就调用SecurityUtils的getSecurityManager从全局中取。显然这个函数再第一次调用的时候是找不到SecurityManager的,因此要返回到ensureSecurityManager进行设置。这样,执行完ensureSecurityManager后,SecurityManager和SubjectContext就关联起来了。
resolveSession
resolveSession定义在DefaultSecurityManager中,
protected SubjectContext resolveSession(SubjectContext context) { if (context.resolveSession() != null) { log.debug("Context already contains a session. Returning."); return context; } try { Session session = resolveContextSession(context); if (session != null) { context.setSession(session); } } catch (InvalidSessionException e) { log.debug("Resolved SubjectContext context session is invalid. Ignoring and creating an anonymous " + "(session-less) Subject instance.", e); } return context; }
这个函数和上面的ensureSecurityManager类似,首先调用resolveSession
resolveSession定义在DefaultSubjectContext中,
public Session resolveSession() { Session session = getSession(); if (session == null) { Subject existingSubject = getSubject(); if (existingSubject != null) { session = existingSubject.getSession(false); } } return session; }
这个函数首先从该SubjectContext中获取Session,如果没有,就获取Subject,再从Subject中获取Session,如果找到则返回,否则返回null。因为是第一次调用该函数,所以肯定为null,所以回到resolveSession函数中,接下来进入resolveContextSession函数,构造一个Session,并和该SubjectContext相关联。
resolveContextSession定义在DefaultSecurityManager中,
protected Session resolveContextSession(SubjectContext context) throws InvalidSessionException { SessionKey key = getSessionKey(context); if (key != null) { return getSession(key); } return null; }
protected SessionKey getSessionKey(SubjectContext context) { Serializable sessionId = context.getSessionId(); if (sessionId != null) { return new DefaultSessionKey(sessionId); } return null; }
这里首先获取sessionId ,这里第一次调用也为null,因此直接返回null。因此resolveSession啥也没干。
resolvePrincipals
resolvePrincipals定义在DefaultSecurityManager中,
protected SubjectContext resolvePrincipals(SubjectContext context) { PrincipalCollection principals = context.resolvePrincipals(); if (CollectionUtils.isEmpty(principals)) { log.trace("No identity (PrincipalCollection) found in the context. Looking for a remembered identity."); principals = getRememberedIdentity(context); if (!CollectionUtils.isEmpty(principals)) { log.debug("Found remembered PrincipalCollection. Adding to the context to be used " + "for subject construction by the SubjectFactory."); context.setPrincipals(principals); } else { log.trace("No remembered identity found. Returning original context."); } } return context; }
首先通过resolvePrincipals尝试获取PrincipalCollection,resolvePrincipals定义在DefaultSubjectContext中,
public PrincipalCollection resolvePrincipals() { PrincipalCollection principals = getPrincipals(); if (CollectionUtils.isEmpty(principals)) { AuthenticationInfo info = getAuthenticationInfo(); if (info != null) { principals = info.getPrincipals(); } } if (CollectionUtils.isEmpty(principals)) { Subject subject = getSubject(); if (subject != null) { principals = subject.getPrincipals(); } } if (CollectionUtils.isEmpty(principals)) { Session session = resolveSession(); if (session != null) { principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY); } } return principals; }
该代码依次尝试从SubjectContext、AuthenticationInfo、Subject和Session中获取PrincipalCollection。这里显然为null,因此返回到resolvePrincipals中,通过getRememberedIdentity获取。
getRememberedIdentity定义在DefaultSecurityManager中,
protected PrincipalCollection getRememberedIdentity(SubjectContext subjectContext) { RememberMeManager rmm = getRememberMeManager(); if (rmm != null) { try { return rmm.getRememberedPrincipals(subjectContext); } catch (Exception e) { if (log.isWarnEnabled()) { String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + "] threw an exception during getRememberedPrincipals()."; log.warn(msg, e); } } } return null; }
getRememberMeManager首先从DefaultWebSecurityManager中获取RememberMeManager,在前面分析的DefaultWebSecurityManager构造函数中可知,getRememberMeManager将会返回CookieRememberMeManager,因此下面看getRememberedPrincipals函数,getRememberedPrincipals定义在CookieRememberMeManager的父类AbstractRememberMeManager中,
public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) { PrincipalCollection principals = null; try { byte[] bytes = getRememberedSerializedIdentity(subjectContext); if (bytes != null && bytes.length > 0) { principals = convertBytesToPrincipals(bytes, subjectContext); } } catch (RuntimeException re) { principals = onRememberedPrincipalFailure(re, subjectContext); } return principals; }
getRememberedSerializedIdentity定义在CookieRememberMeManager中,
protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) { if (!WebUtils.isHttp(subjectContext)) { if (log.isDebugEnabled()) { String msg = "SubjectContext argument is not an HTTP-aware instance. This is required to obtain a " + "servlet request and response in order to retrieve the rememberMe cookie. Returning " + "immediately and ignoring rememberMe operation."; log.debug(msg); } return null; } WebSubjectContext wsc = (WebSubjectContext) subjectContext; if (isIdentityRemoved(wsc)) { return null; } HttpServletRequest request = WebUtils.getHttpRequest(wsc); HttpServletResponse response = WebUtils.getHttpResponse(wsc); String base64 = getCookie().readValue(request, response); if (Cookie.DELETED_COOKIE_VALUE.equals(base64)) return null; if (base64 != null) { base64 = ensurePadding(base64); if (log.isTraceEnabled()) { log.trace("Acquired Base64 encoded identity [" + base64 + "]"); } byte[] decoded = Base64.decode(base64); if (log.isTraceEnabled()) { log.trace("Base64 decoded byte array length: " + (decoded != null ? decoded.length : 0) + " bytes."); } return decoded; } else { return null; } }
这里传入的参数并不是WebSubjectContext,因此会在第一个if内直接返回。因此层层往上返回到resolvePrincipals,最后啥也没做。
doCreateSubject
protected Subject doCreateSubject(SubjectContext context) { return getSubjectFactory().createSubject(context); }
getSubjectFactory()返回前面构造的DefaultWebSubjectFactory,因此createSubject定义在DefaultWebSubjectFactory中如下
public Subject createSubject(SubjectContext context) { if (!(context instanceof WebSubjectContext)) { return super.createSubject(context); } WebSubjectContext wsc = (WebSubjectContext) context; SecurityManager securityManager = wsc.resolveSecurityManager(); Session session = wsc.resolveSession(); boolean sessionEnabled = wsc.isSessionCreationEnabled(); PrincipalCollection principals = wsc.resolvePrincipals(); boolean authenticated = wsc.resolveAuthenticated(); String host = wsc.resolveHost(); ServletRequest request = wsc.resolveServletRequest(); ServletResponse response = wsc.resolveServletResponse(); return new WebDelegatingSubject(principals, authenticated, host, session, sessionEnabled, request, response, securityManager); }
因为这时context并不是WebSubjectContext,因此直接调用父类DefaultSubjectFactory的createSubject函数,
public Subject createSubject(SubjectContext context) { SecurityManager securityManager = context.resolveSecurityManager(); Session session = context.resolveSession(); boolean sessionCreationEnabled = context.isSessionCreationEnabled(); PrincipalCollection principals = context.resolvePrincipals(); boolean authenticated = context.resolveAuthenticated(); String host = context.resolveHost(); return new DelegatingSubject(principals, authenticated, host, session, sessionCreationEnabled, securityManager); }
这里大部分参数都为null,然后直接调用了DelegatingSubject的构造函数。因此,回到doCreateSubject函数,这里就是构造了一个DelegatingSubject函数。
save
protected void save(Subject subject) { this.subjectDAO.save(subject); }
这里的subjectDAO是在前面构造函数中构造的DefaultSubjectDAO,因此看DefaultSubjectDAO的save函数,
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; }
isSessionStorageEnabled也定义在DefaultSubjectDAO中,
protected boolean isSessionStorageEnabled(Subject subject) { return getSessionStorageEvaluator().isSessionStorageEnabled(subject); }
getSessionStorageEvaluator返回在DefaultSubjectDAO的构造函数中构造的DefaultSessionStorageEvaluator,因此接着看它的isSessionStorageEnabled函数,
public boolean isSessionStorageEnabled(Subject subject) { return (subject != null && subject.getSession(false) != null) || isSessionStorageEnabled(); }
这里isSessionStorageEnabled默认的返回true,因此回到save中,接着看saveToSession,
protected void saveToSession(Subject subject) { mergePrincipals(subject); mergeAuthenticationState(subject); }
该函数就是将Subject的状态存在Session中,首先看mergePrincipals函数,
protected void mergePrincipals(Subject subject) { PrincipalCollection currentPrincipals = null; if (subject.isRunAs() && subject instanceof DelegatingSubject) { try { Field field = DelegatingSubject.class.getDeclaredField("principals"); field.setAccessible(true); currentPrincipals = (PrincipalCollection)field.get(subject); } catch (Exception e) { throw new IllegalStateException("Unable to access DelegatingSubject principals property.", e); } } if (currentPrincipals == null || currentPrincipals.isEmpty()) { currentPrincipals = subject.getPrincipals(); } Session session = subject.getSession(false); if (session == null) { if (!CollectionUtils.isEmpty(currentPrincipals)) { session = subject.getSession(); session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, currentPrincipals); } } else { PrincipalCollection existingPrincipals = (PrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); if (CollectionUtils.isEmpty(currentPrincipals)) { if (!CollectionUtils.isEmpty(existingPrincipals)) { session.removeAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); } } else { if (!currentPrincipals.equals(existingPrincipals)) { session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, currentPrincipals); } } } }
首先,在前面doCreateSubject中构造的确实是一个DelegatingSubject,这里isRunAs会返回false,至于为什么,这里就不分析了。下面会进入第二个if,currentPrincipals会被赋值为null(查看之前构造的DelegatingSubject)。下面看Subject的getSession函数,
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) { 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; }
这里传入的参数create为false,因此不会构造session,因此返回null。本章最后假设create为true,分析如何构造该Session。返回到mergePrincipals函数,因为session和currentPrincipals都为null,因此直接返回。所以第一次进入mergePrincipals函数,什么都没做。
回到saveToSession函数,再看mergeAuthenticationState函数,
protected void mergeAuthenticationState(Subject subject) { Session session = subject.getSession(false); if (session == null) { if (subject.isAuthenticated()) { session = subject.getSession(); session.setAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY, Boolean.TRUE); } } else { 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); } } } }
和前面的分析类似,这里也什么也没做。
bind
回到最前头看SecurityUtils的getSubject函数,最后调用了ThreadContext的bind函数,
public static void bind(Subject subject) { if (subject != null) { put(SUBJECT_KEY, subject); } }
看一下put,定义在ThreadContext中,
public static void put(Object key, Object value) { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } if (value == null) { remove(key); return; } ensureResourcesInitialized(); resources.get().put(key, value); if (log.isTraceEnabled()) { String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + key + "] to thread " + "[" + Thread.currentThread().getName() + "]"; log.trace(msg); } }
ensureResourcesInitialized就是初始化resources了,
private static void ensureResourcesInitialized(){ if (resources.get() == null){ resources.set(new HashMap<Object, Object>()); } }
因此最后就是简单地将刚刚构造的Subject(其实是DelegatingSubject)放入resources中。
- Shiro使用和源码分析---5
- Shiro使用和源码分析---5
- Shiro使用和源码分析---1
- Shiro使用和源码分析---3
- Shiro使用和源码分析---4
- Shiro使用和源码分析---6
- Shiro使用和源码分析---7
- Shiro使用和源码分析---1
- Shiro使用和源码分析---3
- Shiro使用和源码分析---4
- Shiro使用和源码分析---6
- Shiro使用和源码分析---7
- 使用shiro和redis结合,管理SessionDAO的对Session的CRUD,并源码分析
- Shiro源码分析
- Shiro使用和原理分析---2
- Shiro使用和原理分析---2
- shiro源码分析(二)Subject和Session
- Shiro源码分析-初始化-Realm
- react native image resizeMode理解
- 杭电2896题 AC自动机模板题
- A. Vitaly and Night
- 网络流小结
- 收藏两篇关于theano配置和CUDA加速的博客
- Shiro使用和源码分析---5
- Input Axis Mouse X is not setup.
- 新手学EasyUI(七)----DataGrid CheckBox 动态选中
- C++基础::关于区间端点的问题
- 杭电1069--Monkey and Banana 子序列,dp
- lamp 环境搭建遇到的问题
- kworker内核工作队列详解
- codeforces GYM 100792H
- AC自动机模板