欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
shiro源碼分析(二)Subject和Session

繼續上一篇文章的案例,第一次使用SecurityUtils.getSubject()來(lái)獲取Subject時(shí)

public static Subject getSubject() {        Subject subject = ThreadContext.getSubject();        if (subject == null) {            subject = (new Subject.Builder()).buildSubject();            ThreadContext.bind(subject);        }        return subject;    }

使用ThreadLocal模式來(lái)獲取,若沒(méi)有則創(chuàng )建一個(gè)并綁定到當前線(xiàn)程。此時(shí)創(chuàng )建使用的是Subject內部類(lèi)Builder來(lái)創(chuàng )建的,Builder會(huì )創(chuàng )建一個(gè)SubjectContext接口的實(shí)例DefaultSubjectContext,最終會(huì )委托securityManager來(lái)根據SubjectContext信息來(lái)創(chuàng )建一個(gè)Subject,下面詳細說(shuō)下該過(guò)程,在DefaultSecurityManager的createSubject方法中:

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;    }

首先就是復制SubjectContext,SubjectContext 接口繼承了Map<String, Object>,然后加入了幾個(gè)重要的SecurityManager、SessionId、Subject、PrincipalCollection、Session、boolean authenticated、boolean sessionCreationEnabled、Host、AuthenticationToken、AuthenticationInfo等眾多信息。

然后來(lái)討論下接口設計:


討論1:首先是SubjectContext為什么要去實(shí)現Map<String, Object>?
SubjectContext提供了常用的get、set方法,還提供了一個(gè)resolve方法,以SecurityManager為例:

SecurityManager getSecurityManager();    void setSecurityManager(SecurityManager securityManager);    SecurityManager resolveSecurityManager();

這些get、set方法則用于常用的設置和獲取,而resolve則表示先調用getSecurityManager,如果獲取不到,則使用其他途徑來(lái)獲取,如DefaultSubjectContext的實(shí)現:

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;    }

如果getSecurityManager獲取不到,則使用SecurityUtils工具來(lái)獲取。
再如resolvePrincipals

public PrincipalCollection resolvePrincipals() {        PrincipalCollection principals = getPrincipals();        if (CollectionUtils.isEmpty(principals)) {            //check to see if they were just authenticated:            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)) {            //try the session:            Session session = resolveSession();            if (session != null) {                principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);            }        }        return principals;    }

普通的getPrincipals()獲取不到,嘗試使用其他屬性來(lái)獲取。
討論2:此時(shí)就有一個(gè)問(wèn)題,有必要再對外公開(kāi)getPrincipals方法嗎?什么情況下外界會(huì )去調用getPrincipals方法而不會(huì )去調用resolvePrincipals方法?

然后我們繼續回到上面的類(lèi)圖設計上:
DefaultSubjectContext繼承了MapContext,MapContext又實(shí)現了Map<String, Object>,看下此時(shí)的MapContext有什么東西:

public class MapContext implements Map<String, Object>, Serializable {    private static final long serialVersionUID = 5373399119017820322L;    private final Map<String, Object> backingMap;    public MapContext() {        this.backingMap = new HashMap<String, Object>();    }    public MapContext(Map<String, Object> map) {        this();        if (!CollectionUtils.isEmpty(map)) {            this.backingMap.putAll(map);        }    }  //略}

MapContext內部擁有一個(gè)類(lèi)型為HashMap的backingMap屬性,大部分方法都由HashMap來(lái)實(shí)現,然后僅僅更改某些行為,MapContext沒(méi)有選擇去繼承HashMap,而是使用了組合的方式,更加容易去擴展,如backingMap的類(lèi)型不一定非要選擇HashMap,可以換成其他的Map實(shí)現,一旦MapContext選擇繼承HashMap,如果想對其他的Map類(lèi)型進(jìn)行同樣的功能增強的話(huà),就需要另寫(xiě)一個(gè)類(lèi)來(lái)繼承它然后改變一些方法實(shí)現,這樣的話(huà)就會(huì )有很多重復代碼。這也是設計模式所強調的少用繼承多用組合。但是MapContext的寫(xiě)法使得子類(lèi)沒(méi)法去替換HashMap,哎,心塞 。
MapContext又提供了如下幾個(gè)返回值不可修改的方法:

public Set<String> keySet() {        return Collections.unmodifiableSet(backingMap.keySet());    }    public Collection<Object> values() {        return Collections.unmodifiableCollection(backingMap.values());    }    public Set<Entry<String, Object>> entrySet() {        return Collections.unmodifiableSet(backingMap.entrySet());    }

有點(diǎn)扯遠了。繼續回到DefaultSecurityManager創(chuàng )建Subject的地方:

public Subject createSubject(SubjectContext subjectContext) {        //create a copy so we don't modify the argument's backing map:        SubjectContext context = copy(subjectContext);        //ensure that the context has a SecurityManager instance, and if not, add one:        context = ensureSecurityManager(context);        //Resolve an associated Session (usually based on a referenced session ID), and place it in the context before        //sending to the SubjectFactory.  The SubjectFactory should not need to know how to acquire sessions as the        //process is often environment specific - better to shield the SF from these details:        context = resolveSession(context);        //Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first        //if possible before handing off to the SubjectFactory:        context = resolvePrincipals(context);        Subject subject = doCreateSubject(context);        //save this subject for future reference if necessary:        //(this is needed here in case rememberMe principals were resolved and they need to be stored in the        //session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).        //Added in 1.2:        save(subject);        return subject;    }

對于context,把能獲取到的參數都湊齊,SecurityManager、Session。resolveSession嘗試獲取context的map中獲取Session,若沒(méi)有則嘗試獲取context的map中的Subject,如果存在的話(huà),根據此Subject來(lái)獲取Session,若沒(méi)有再?lài)L試獲取sessionId,若果有了sessionId則構建成一個(gè)DefaultSessionKey來(lái)獲取對應的Session。
整個(gè)過(guò)程如下;

protected SubjectContext resolveSession(SubjectContext context) {        if (context.resolveSession() != null) {            log.debug("Context already contains a session.  Returning.");            return context;        }        try {            //Context couldn't resolve it directly, let's see if we can since we have direct access to            //the session manager:            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;    }

先看下context.resolveSession():

public Session resolveSession() {  //這里則是直接從map中取出Session        Session session = getSession();        if (session == null) {            //try the Subject if it exists:           //若果沒(méi)有,嘗試從map中取出Subject            Subject existingSubject = getSubject();            if (existingSubject != null) {                //這里就是Subject獲取session的方法,需要詳細看下                session = existingSubject.getSession(false);            }        }        return session;    }

existingSubject.getSession(false):通過(guò)Subject獲取Session如下

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;    }

getSession()的參數表示是否創(chuàng )建session,如果Session為空,并且傳遞的參數為true,則會(huì )創(chuàng )建一個(gè)Session。然而這里傳遞的是false,也就是說(shuō)不會(huì )在創(chuàng )建Subject的時(shí)候來(lái)創(chuàng )建Session,所以把創(chuàng )建Session過(guò)程說(shuō)完后,再回到此處是要記著(zhù)不會(huì )去創(chuàng )建一個(gè)Session。但是我們可以來(lái)看下是如何創(chuàng )建Session的,整體三大步驟,先創(chuàng )建一個(gè)SessionContext ,然后根據SessionContext 來(lái)創(chuàng )建Session,最后是裝飾Session,由于創(chuàng )建Session過(guò)程內容比較多,先說(shuō)說(shuō)裝飾Session。

protected Session decorate(Session session) {        if (session == null) {            throw new IllegalArgumentException("session cannot be null");        }        return new StoppingAwareProxiedSession(session, this);    }

裝飾Session就是講Session和DelegatingSubject封裝起來(lái)。
然后來(lái)說(shuō)Session的創(chuàng )建過(guò)程,這和Subject的創(chuàng )建方式差不多。
同樣是SessionContext的接口設計:



和SubjectContext相當雷同。
看下SessionContext的主要內容:

void setHost(String host);    String getHost();    Serializable getSessionId();    void setSessionId(Serializable sessionId);

主要兩個(gè)內容,host和sessionId。
接下來(lái)看下如何由SessionContext來(lái)創(chuàng )建Session:

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);    }

和Subject一樣也是由一個(gè)SessionFactory根據SessionContext來(lái)創(chuàng )建出一個(gè)Session,看下默認的SessionFactory SimpleSessionFactory的創(chuàng )建過(guò)程:

public Session createSession(SessionContext initData) {        if (initData != null) {            String host = initData.getHost();            if (host != null) {                return new SimpleSession(host);            }        }        return new SimpleSession();    }

如果SessionContext有host信息,就傳遞給Session,然后就是直接new一個(gè)Session接口的實(shí)現SimpleSession,先看下Session接口有哪些內容:

public interface Session {    Serializable getId();    Date getStartTimestamp();    Date getLastAccessTime();    long getTimeout() throws InvalidSessionException;    void setTimeout(long maxIdleTimeInMillis) throws InvalidSessionException;    String getHost();    void touch() throws InvalidSessionException;    void stop() throws InvalidSessionException;    Collection<Object> getAttributeKeys() throws InvalidSessionException;    Object getAttribute(Object key) throws InvalidSessionException;    void setAttribute(Object key, Object value) throws InvalidSessionException;    Object removeAttribute(Object key) throws InvalidSessionException;}

id:Session的唯一標識,創(chuàng )建時(shí)間、超時(shí)時(shí)間等內容。
再看SimpleSession的創(chuàng )建過(guò)程:

public SimpleSession() {        this.timeout = DefaultSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT;        this.startTimestamp = new Date();        this.lastAccessTime = this.startTimestamp;    }    public SimpleSession(String host) {        this();        this.host = host;    }

設置下超時(shí)時(shí)間為DefaultSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT 30分鐘,startTimestamp 和lastAccessTime設置為現在開(kāi)始。就這樣構建出了一個(gè)Session的實(shí)例,然后就是需要將該實(shí)例保存起來(lái):

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 void create(Session session) {        if (log.isDebugEnabled()) {            log.debug("Creating new EIS record for new session instance [" + session + "]");        }        sessionDAO.create(session);    }

即該進(jìn)行create(s)操作了,又和Subject極度的相像,使用sessionDAO來(lái)保存剛才創(chuàng )建的Session。再來(lái)看下SessionDAO接口:

public interface SessionDAO {    Serializable create(Session session);    Session readSession(Serializable sessionId) throws UnknownSessionException;    void update(Session session) throws UnknownSessionException;    void delete(Session session);    Collection<Session> getActiveSessions();}

也就是對所有的Session進(jìn)行增刪該查,SessionDAO 接口繼承關(guān)系如下:



AbstractSessionDAO:有一個(gè)重要的屬性SessionIdGenerator,它負責給Session創(chuàng )建sessionId,SessionIdGenerator接口如下:

public interface SessionIdGenerator {    Serializable generateId(Session session);}

很簡(jiǎn)單,參數為Session,返回sessionId。SessionIdGenerator 的實(shí)現有兩個(gè)JavaUuidSessionIdGenerator、RandomSessionIdGenerator。而AbstractSessionDAO默認采用的是JavaUuidSessionIdGenerator,如下:

public AbstractSessionDAO() {        this.sessionIdGenerator = new JavaUuidSessionIdGenerator();    }

MemorySessionDAO繼承了AbstractSessionDAO,它把Session存儲在一個(gè)ConcurrentMap<Serializable, Session> sessions集合中,key為sessionId,value為Session。
CachingSessionDAO:主要配合在別的地方存儲session。先不介紹,之后的文章再詳細說(shuō)。
對于本案例來(lái)說(shuō)SessionDAO為MemorySessionDAO。至此整個(gè)Session的創(chuàng )建過(guò)程就走通了。

剛才雖然說(shuō)了整個(gè)Session的創(chuàng )建過(guò)程,回到上文所說(shuō)的,不會(huì )去創(chuàng )建Session的地方。在創(chuàng )建Subject搜集session信息時(shí),使用的此時(shí)的Subject的Session、sessionId都為空,所以獲取不到Session。然后就是doCreateSubject:

protected Subject doCreateSubject(SubjectContext context) {        return getSubjectFactory().createSubject(context);    }

就是通過(guò)SubjectFactory工廠(chǎng)接口來(lái)創(chuàng )建Subject的,而DefaultSecurityManager默認使用的
SubjectFactory是DefaultSubjectFactory:

public DefaultSecurityManager() {        super();        this.subjectFactory = new DefaultSubjectFactory();        this.subjectDAO = new DefaultSubjectDAO();    }

繼續看DefaultSubjectFactory是怎么創(chuàng )建Subject的:

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);    }

仍然就是將這些屬性傳遞給DelegatingSubject,也沒(méi)什么好說(shuō)的。創(chuàng )建完成之后,就需要將剛創(chuàng )建的Subject保存起來(lái),仍回到:

public Subject createSubject(SubjectContext subjectContext) {        //create a copy so we don't modify the argument's backing map:        SubjectContext context = copy(subjectContext);        //ensure that the context has a SecurityManager instance, and if not, add one:        context = ensureSecurityManager(context);        //Resolve an associated Session (usually based on a referenced session ID), and place it in the context before        //sending to the SubjectFactory.  The SubjectFactory should not need to know how to acquire sessions as the        //process is often environment specific - better to shield the SF from these details:        context = resolveSession(context);        //Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first        //if possible before handing off to the SubjectFactory:        context = resolvePrincipals(context);        Subject subject = doCreateSubject(context);        //save this subject for future reference if necessary:        //(this is needed here in case rememberMe principals were resolved and they need to be stored in the        //session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).        //Added in 1.2:        save(subject);        return subject;    }

來(lái)看下save方法:

protected void save(Subject subject) {        this.subjectDAO.save(subject);    }

可以看到又是使用另一個(gè)模塊來(lái)完成的即SubjectDAO,SubjectDAO接口如下:

public interface SubjectDAO {    Subject save(Subject subject);    void delete(Subject subject);}

很簡(jiǎn)單,就是保存和刪除一個(gè)Subject。我們看下具體的實(shí)現類(lèi)DefaultSubjectDAO是如何來(lái)保存的:

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,是否要存儲該Subject的session來(lái)
DefaultSubjectDAO:有一個(gè)重要屬性SessionStorageEvaluator,它是用來(lái)決定一個(gè)Subject的Session來(lái)記錄Subject的狀態(tài),接口如下

public interface SessionStorageEvaluator {    boolean isSessionStorageEnabled(Subject subject);}

其實(shí)現為DefaultSessionStorageEvaluator:

public class DefaultSessionStorageEvaluator implements SessionStorageEvaluator {    private boolean sessionStorageEnabled = true;    public boolean isSessionStorageEnabled(Subject subject) {        return (subject != null && subject.getSession(false) != null) || isSessionStorageEnabled();    }

決定策略就是通過(guò)DefaultSessionStorageEvaluator 的sessionStorageEnabled的true或false 和subject是否有Session對象來(lái)決定的。如果允許存儲Subject的Session的話(huà),下面就說(shuō)具體的存儲過(guò)程:

protected void saveToSession(Subject subject) {        //performs merge logic, only updating the Subject's session if it does not match the current state:        mergePrincipals(subject);        mergeAuthenticationState(subject);    }protected void mergePrincipals(Subject subject) {        //merge PrincipalCollection state:        PrincipalCollection currentPrincipals = null;        //SHIRO-380: added if/else block - need to retain original (source) principals        //This technique (reflection) is only temporary - a proper long term solution needs to be found,        //but this technique allowed an immediate fix that is API point-version forwards and backwards compatible        //        //A more comprehensive review / cleaning of runAs should be performed for Shiro 1.3 / 2.0 +        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) {           //只有當Session為空,并且currentPrincipals不為空的時(shí)候才會(huì )去創(chuàng  )建Session           //Subject subject = SecurityUtils.getSubject()此時(shí)兩者都是為空的,           //不會(huì )去創(chuàng  )建Session            if (!CollectionUtils.isEmpty(currentPrincipals)) {                session = subject.getSession();                session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, currentPrincipals);            }            //otherwise no session and no principals - nothing to save        } else {            PrincipalCollection existingPrincipals =                    (PrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);            if (CollectionUtils.isEmpty(currentPrincipals)) {                if (!CollectionUtils.isEmpty(existingPrincipals)) {                    session.removeAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);                }                //otherwise both are null or empty - no need to update the session            } else {                if (!currentPrincipals.equals(existingPrincipals)) {                    session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, currentPrincipals);                }                //otherwise they're the same - no need to update the session            }        }    }

上面有我們關(guān)心的重點(diǎn),當subject.getSession(false)獲取的Session為空時(shí)(它不會(huì )去創(chuàng )建Session),此時(shí)就需要去創(chuàng )建Session,subject.getSession()則默認調用的是subject.getSession(true),則會(huì )進(jìn)行Session的創(chuàng )建,創(chuàng )建過(guò)程上文已詳細說(shuō)明了。
在第一次創(chuàng )建Subject的時(shí)候

Subject subject = SecurityUtils.getSubject();

雖然Session為空,但此時(shí)還沒(méi)有用戶(hù)身份信息,也不會(huì )去創(chuàng )建Session。案例中的subject.login(token),該過(guò)程則會(huì )去創(chuàng )建Session,具體看下過(guò)程:

public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {        AuthenticationInfo info;        try {            info = authenticate(token);        } catch (AuthenticationException ae) {            try {                onFailedLogin(token, ae, subject);            } catch (Exception e) {                if (log.isInfoEnabled()) {                    log.info("onFailedLogin method threw an " +                            "exception.  Logging and propagating original AuthenticationException.", e);                }            }            throw ae; //propagate        }         //在該過(guò)程會(huì )進(jìn)行Session的創(chuàng  )建        Subject loggedIn = createSubject(token, info, subject);        onSuccessfulLogin(token, info, loggedIn);        return loggedIn;    }

對于驗證過(guò)程上篇文章已經(jīng)簡(jiǎn)單說(shuō)明了,這里不再說(shuō)明,重點(diǎn)還是在驗證通過(guò)后,會(huì )設置Subject的身份,即用戶(hù)名:

protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {        SubjectContext context = createSubjectContext();        context.setAuthenticated(true);        context.setAuthenticationToken(token);        context.setAuthenticationInfo(info);        if (existing != null) {            context.setSubject(existing);        }        return createSubject(context);    }

有了認證成功的AuthenticationInfo信息,SubjectContext在resolvePrincipals便可以獲取用戶(hù)信息,即通過(guò)AuthenticationInfo的getPrincipals()來(lái)獲得。

public PrincipalCollection resolvePrincipals() {        PrincipalCollection principals = getPrincipals();        if (CollectionUtils.isEmpty(principals)) {            //check to see if they were just authenticated:            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)) {            //try the session:            Session session = resolveSession();            if (session != null) {                principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);            }        }        return principals;    }

PrincipalCollection不為空了,在save(subject)的時(shí)候會(huì )得到session為空,同時(shí)PrincipalCollection不為空,則會(huì )執行Session的創(chuàng )建。也就是說(shuō)在認證通過(guò)后,會(huì )執行Session的創(chuàng )建,Session創(chuàng )建完成之后會(huì )進(jìn)行一次裝飾,即用StoppingAwareProxiedSession將創(chuàng )建出來(lái)的session和subject關(guān)聯(lián)起來(lái),然后又進(jìn)行如下操作:

public void login(AuthenticationToken token) throws AuthenticationException {        clearRunAsIdentitiesInternal();        //這里的Subject則是經(jīng)過(guò)認證后創(chuàng  )建的并且也含有剛才創(chuàng  )建的session,類(lèi)型為        //StoppingAwareProxiedSession,即是該subject本身和session的合體。        Subject subject = securityManager.login(this, token);        PrincipalCollection principals;        String host = null;        if (subject instanceof DelegatingSubject) {            DelegatingSubject delegating = (DelegatingSubject) subject;            //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals:            principals = delegating.principals;            host = delegating.host;        } else {            principals = subject.getPrincipals();        }        if (principals == null || principals.isEmpty()) {            String msg = "Principals returned from securityManager.login( token ) returned a null or " +                    "empty value.  This value must be non null and populated with one or more elements.";            throw new IllegalStateException(msg);        }        this.principals = principals;        this.authenticated = true;        if (token instanceof HostAuthenticationToken) {            host = ((HostAuthenticationToken) token).getHost();        }        if (host != null) {            this.host = host;        }        Session session = subject.getSession(false);        if (session != null) {            //在這里可以看到又進(jìn)行了一次裝飾            this.session = decorate(session);        } else {            this.session = null;        }    }

subject 創(chuàng )建出來(lái)之后,暫且叫內部subject,就是把認證通過(guò)的內部subject的信息和session復制給我們外界使用的subject.login(token)的subject中,這個(gè)subject暫且叫外部subject,看下session的賦值,又進(jìn)行了一次裝飾,這次裝飾則把session(類(lèi)型為StoppingAwareProxiedSession,即是內部subject和session的合體)和外部subject綁定到一起。
最后來(lái)總結下,首先是Subject和Session的接口類(lèi)圖:



然后就是Subject subject = SecurityUtils.getSubject()的一個(gè)簡(jiǎn)易的流程圖:

最后是subject.login(token)的簡(jiǎn)易流程圖:




作者:乒乓狂魔

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Shiro與CAS整合實(shí)現單點(diǎn)登錄
Shiro框架Web環(huán)境下過(guò)濾器結構分析
第四章:Shiro的身份認證(Authentication)
我的shiro之旅: 十四 shiro 自動(dòng)登錄
JAVA|多Realm管理基礎實(shí)現
Shiro 學(xué)習
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久