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中。

0 0
原创粉丝点击