2.详解SecurityManager(shiro权限管理门面)

SecurityManager 接口主要作用
为什么要先说SecurityManager呢?因为我觉得他是shiro的主要入口,几乎所有相关的权限操作,都由他代理了。
1.可以说是所有配置的入口,简化配置,方便使用。
2.一个接口就可以实现,验证的操作(登录、退出)、授权(授权访问指定资源、角色)、Session管理,相当于这些操作的门面(门面模式,也叫外观模式)。

这里写图片描述

从上图我们可以看出SecurityManager各个子类的作用及子类的依赖组件的接口。下面我们底层子类往上推,分别详解各个子类的作用
1. CachingSecurityManager

//该抽象类实现类CacheManagerAware 接口,主要提供缓存支持,管理缓存操作
public abstract class CachingSecurityManager implements SecurityManager, Destroyable, CacheManagerAware {
    //缓存接口的实现类,实现可以是ehcache,java的HashMap版的cacheManager,redis
    private CacheManager cacheManager;

    //通过该接口可以获取cacheManager,然后使用它来做一些你所需的操作,如进行一些自定义的缓存管理
    public CacheManager getCacheManager() {
        return cacheManager;
    }

    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
        //在设置cacheManager后,执行一些后续操作。该后续操作主要是:设置cacheManagr到Realm和SessionManager等相关依cacheManagr的类
        afterCacheManagerSet();
    }

    //Template 方法,让子类重写实现业务逻辑
    protected void afterCacheManagerSet() {
    }
    //销毁SecurityManager时,销毁该缓存实例
    public void destroy() {
        LifecycleUtils.destroy(getCacheManager());
        this.cacheManager = null;
    }

}

2.RealmSecurityManager

//该抽象类主要是管理Realm(可以理解为数据处理组件,比如Realm根据用户名查找底层数据库,然后取出来和你输入的用户密码进行批评,验证是否equals来验证是否登陆成功,还有授权数据等)
public abstract class RealmSecurityManager extends CachingSecurityManager {
    //至少需要一个Realm,可以是多个。相当于多个数据处理中心,比如mysql数据库,redis数据库
    private Collection<Realm> realms;

    public void setRealm(Realm realm) {
        if (realm == null) {
            throw new IllegalArgumentException("Realm argument cannot be null");
        }
        Collection<Realm> realms = new ArrayList<Realm>(1);
        realms.add(realm);
        setRealms(realms);
    }


    public void setRealms(Collection<Realm> realms) {
        if (realms == null) {
            throw new IllegalArgumentException("Realms collection argument cannot be null.");
        }
        if (realms.isEmpty()) {
            throw new IllegalArgumentException("Realms collection argument cannot be empty.");
        }
        this.realms = realms;
        //模板方法,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中
        afterRealmsSet();
    }

    protected void afterRealmsSet() {
        applyCacheManagerToRealms();
    }

    //获取realm,根据你是否有需求来决定使用。可能应用场景:从Realm中获取用户的授权、验证的缓存信息
    public Collection<Realm> getRealms() {
        return realms;
    }

   //设置cacheManager到Realm中,因为Realm是数据处理组件,当它从数据库中加载数据且得到正确的验证后,可以缓存到cacheManager,来提供性能。在shiro里,AuthorizationInfo(授权数据)和AuthenticationInfo(用户基本账户密码)都被缓存到cacheManager在验证成功后
    protected void applyCacheManagerToRealms() {
        CacheManager cacheManager = getCacheManager();
        Collection<Realm> realms = getRealms();
        if (cacheManager != null && realms != null && !realms.isEmpty()) {
            for (Realm realm : realms) {
                if (realm instanceof CacheManagerAware) {
                    ((CacheManagerAware) realm).setCacheManager(cacheManager);
                }
            }
        }
    }
    protected void afterCacheManagerSet() {
        applyCacheManagerToRealms();
    }
    //销毁realms
    public void destroy() {
        LifecycleUtils.destroy(getRealms());
        this.realms = null;
        super.destroy();
    }

}

3.AuthenticatingSecurityManager

//实现接口Authenticator,处理用户登陆验证的 SecurityManager 的 抽象实现,仅仅代理Authenticator.
public abstract class AuthenticatingSecurityManager extends RealmSecurityManager {

    //依赖authenticator验证器,真正的登陆验证都在这里面处理
    private Authenticator authenticator;


    public AuthenticatingSecurityManager() {
        super();
    //默认的Authenticator,在大多数情况下,该默认实例足够用了
        this.authenticator = new ModularRealmAuthenticator();
    }


    public Authenticator getAuthenticator() {
        return authenticator;
    }

    //覆盖默认的ModularRealmAuthenticator
    public void setAuthenticator(Authenticator authenticator) throws IllegalArgumentException {
        if (authenticator == null) {
            String msg = "Authenticator argument cannot be null.";
            throw new IllegalArgumentException(msg);
        }
        this.authenticator = authenticator;
    }

    //重写父类模板方法
    protected void afterRealmsSet() {
        super.afterRealmsSet();
        if (this.authenticator instanceof ModularRealmAuthenticator) {
            ((ModularRealmAuthenticator) this.authenticator).setRealms(getRealms());
        }
    }

    //该类的核心,调用底层的authenticator进行用户输入的账户密码验证
    //token 是用户输入的账户密码
    public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
        return this.authenticator.authenticate(token);
    }

    //销毁Authenticator
    public void destroy() {
        LifecycleUtils.destroy(getAuthenticator());
        this.authenticator = null;
        super.destroy();
    }
}

4.AuthorizingSecurityManager

//AuthorizingSecurityManager是实现了Authorizer接口的抽象类,该类主要代理Authorizer进行授权。
public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager {

    //真正的授权器
    private Authorizer authorizer;


    public AuthorizingSecurityManager() {
        super();
    //默认的Authorizer,该默认实例支持大部分使用场景
        this.authorizer = new ModularRealmAuthorizer();
    }


    public Authorizer getAuthorizer() {
        return authorizer;
    }

    //覆盖默认的Authorizer
    public void setAuthorizer(Authorizer authorizer) {
        if (authorizer == null) {
            String msg = "Authorizer argument cannot be null.";
            throw new IllegalArgumentException(msg);
        }
        this.authorizer = authorizer;
    }

    //重写父类的afterRealmsSet(),首先调用父类的afterRealmsSet(),然后在设置realms到授权器,如果实现是ModularRealmAuthorizer。也就是说如果你覆盖了默认的
    ModularRealmAuthorizer,那么你要对这个方法进行处理。
    protected void afterRealmsSet() {
        super.afterRealmsSet();
        if (this.authorizer instanceof ModularRealmAuthorizer) {
            ((ModularRealmAuthorizer) this.authorizer).setRealms(getRealms());
        }
    }

    public void destroy() {
        LifecycleUtils.destroy(getAuthorizer());
        this.authorizer = null;
        super.destroy();
    }

    /**
    以下都是调用底层的authorizer来进行授权处理。所有的用户是否能授权其实就是调用以下方法。后面详讲authorizer,会讲解每个方法的意思,大家可以随便看看有个影像就可以了。
    总的来说就两类:一类是返回true false来说明是否授权成功,一个抛异常来说明是否授权成功
    **/
    public boolean isPermitted(PrincipalCollection principals, String permissionString) {
        return this.authorizer.isPermitted(principals, permissionString);
    }

    public boolean isPermitted(PrincipalCollection principals, Permission permission) {
        return this.authorizer.isPermitted(principals, permission);
    }

    public boolean[] isPermitted(PrincipalCollection principals, String... permissions) {
        return this.authorizer.isPermitted(principals, permissions);
    }

    public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) {
        return this.authorizer.isPermitted(principals, permissions);
    }

    public boolean isPermittedAll(PrincipalCollection principals, String... permissions) {
        return this.authorizer.isPermittedAll(principals, permissions);
    }

    public boolean isPermittedAll(PrincipalCollection principals, Collection<Permission> permissions) {
        return this.authorizer.isPermittedAll(principals, permissions);
    }

    public void checkPermission(PrincipalCollection principals, String permission) throws AuthorizationException {
        this.authorizer.checkPermission(principals, permission);
    }

    public void checkPermission(PrincipalCollection principals, Permission permission) throws AuthorizationException {
        this.authorizer.checkPermission(principals, permission);
    }

    public void checkPermissions(PrincipalCollection principals, String... permissions) throws AuthorizationException {
        this.authorizer.checkPermissions(principals, permissions);
    }

    public void checkPermissions(PrincipalCollection principals, Collection<Permission> permissions) throws AuthorizationException {
        this.authorizer.checkPermissions(principals, permissions);
    }

    public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
        return this.authorizer.hasRole(principals, roleIdentifier);
    }

    public boolean[] hasRoles(PrincipalCollection principals, List<String> roleIdentifiers) {
        return this.authorizer.hasRoles(principals, roleIdentifiers);
    }

    public boolean hasAllRoles(PrincipalCollection principals, Collection<String> roleIdentifiers) {
        return this.authorizer.hasAllRoles(principals, roleIdentifiers);
    }

    public void checkRole(PrincipalCollection principals, String role) throws AuthorizationException {
        this.authorizer.checkRole(principals, role);
    }

    public void checkRoles(PrincipalCollection principals, Collection<String> roles) throws AuthorizationException {
        this.authorizer.checkRoles(principals, roles);
    }

    public void checkRoles(PrincipalCollection principals, String... roles) throws AuthorizationException {
        this.authorizer.checkRoles(principals, roles);
    }    
}

5.SessionsSecurityManager

//SessionsSecurityManager实现类SessionManager的方法。代理了SessionManager来处理相关的session操作。
public abstract class SessionsSecurityManager extends AuthorizingSecurityManager {

    //Session管理
    private SessionManager sessionManager;


    public SessionsSecurityManager() {
        super();
    //默认的SessionManager的实现类
        this.sessionManager = new DefaultSessionManager();
    //顾名思义,设置CacheManager到sessionManager
        applyCacheManagerToSessionManager();
    }

     public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
        afterSessionManagerSet();
    }

    //在sessionManager被设置后调用,该类只调用 applyCacheManagerToSessionManager(),大家可以琢磨下这样写的好处,子类可以重写增强等
    protected void afterSessionManagerSet() {
        applyCacheManagerToSessionManager();
    }

    //获取sessionManager,根据你的需求。除了下面的方法,可能使用场景:获取所有在线session
    public SessionManager getSessionManager() {
        return this.sessionManager;
    }

    //增强父类的afterCacheManagerSet(),满足本类需求
    protected void afterCacheManagerSet() {
        super.afterCacheManagerSet();
        applyCacheManagerToSessionManager();
    }

    //如果sessionManager实现了CacheManagerAware,则设置cacheManager
    protected void applyCacheManagerToSessionManager() {
        if (this.sessionManager instanceof CacheManagerAware) {
            ((CacheManagerAware) this.sessionManager).setCacheManager(getCacheManager());
        }
    }

    //调用sessionManager根据上下文context(存储session的相关创建信息,大家可以去了解下上下文)创建个session
    public Session start(SessionContext context) throws AuthorizationException {
        return this.sessionManager.start(context);
    }

    //根据sessionID来获取session,每次生成session后会生成个sessionID返回给浏览器,浏览器用sessionID来和sessionManager进行交互
    public Session getSession(SessionKey key) throws SessionException {
        return this.sessionManager.getSession(key);
    }

    //销毁sessionManager
    public void destroy() {
        LifecycleUtils.destroy(getSessionManager());
        this.sessionManager = null;
        super.destroy();
    }
}

6.DefaultSecurityManager

//默认的SessionManager的具体实现,该实现类会合适的初始化依赖组件。如subjectFactory、SubjectDAO
public class DefaultSecurityManager extends SessionsSecurityManager {

    private static final Logger log = LoggerFactory.getLogger(DefaultSecurityManager.class);

    //是否记住密码服务组件
    protected RememberMeManager rememberMeManager;
    //subject(代理特定的一个用户的所有权限相关操作,登陆退出、授权,获取session等)的管理组件,仅提供了save和delete方法。用于保存subject的状态,方便与以后可以重建subject
    protected SubjectDAO subjectDAO;
    //根据SubjectContext(subject的状态和相关的数据)来创建个subject
    protected SubjectFactory subjectFactory;


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


    public DefaultSecurityManager(Realm singleRealm) {
        this();
        setRealm(singleRealm);
    }

    //realms 调用子类的 setRealms(realms),至少需要一个。
    public DefaultSecurityManager(Collection<Realm> realms) {
        this();
        setRealms(realms);
    }

    //获取subjectFactory,主要用于创建subject
    public SubjectFactory getSubjectFactory() {
        return subjectFactory;
    }


    public void setSubjectFactory(SubjectFactory subjectFactory) {
        this.subjectFactory = subjectFactory;
    }

    //获取subjectDAO,主要用于持久化或者删除subject状态(该状态可用于以后来重建subject)
    public SubjectDAO getSubjectDAO() {
        return subjectDAO;
    }


    public void setSubjectDAO(SubjectDAO subjectDAO) {
        this.subjectDAO = subjectDAO;
    }

    public RememberMeManager getRememberMeManager() {
        return rememberMeManager;
    }

    public void setRememberMeManager(RememberMeManager rememberMeManager) {
        this.rememberMeManager = rememberMeManager;
    }

    protected SubjectContext createSubjectContext() {
        return new DefaultSubjectContext();
    }

    //根据形参,创建个subject。
    //token用户输入的账户密码,info从数据库加载的账户密码
    protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {
    //创建默认的SubjectContext的实现
        SubjectContext context = createSubjectContext();
    //设置context的是否验证、token和info,方便以后调用
        context.setAuthenticated(true);
        context.setAuthenticationToken(token);
        context.setAuthenticationInfo(info);
        if (existing != null) {
            context.setSubject(existing);
        }
        return createSubject(context);
    }

    //shiri1.2之后已被弃用
    @Deprecated
    protected void bind(Subject subject) {
        save(subject);
    }

    //执行RememberMeManager的onSuccessfulLogin(subject, token, info)
    protected void rememberMeSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
        RememberMeManager rmm = getRememberMeManager();
        if (rmm != null) {
            try {
        //记住当前subject, principals
                rmm.onSuccessfulLogin(subject, token, info);
            } catch (Exception e) {
                if (log.isWarnEnabled()) {
                    String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
                            "] threw an exception during onSuccessfulLogin.  RememberMe services will not be " +
                            "performed for account [" + info + "].";
                    log.warn(msg, e);
                }
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("This " + getClass().getName() + " instance does not have a " +
                        "[" + RememberMeManager.class.getName() + "] instance configured.  RememberMe services " +
                        "will not be performed for account [" + info + "].");
            }
        }
    }

    protected void rememberMeFailedLogin(AuthenticationToken token, AuthenticationException ex, Subject subject) {
        RememberMeManager rmm = getRememberMeManager();
        if (rmm != null) {
            try {
            //清除cookie(重置cookie为默认值)
                rmm.onFailedLogin(subject, token, ex);
            } catch (Exception e) {
                if (log.isWarnEnabled()) {
                    String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
                            "] threw an exception during onFailedLogin for AuthenticationToken [" +
                            token + "].";
                    log.warn(msg, e);
                }
            }
        }
    }

    protected void rememberMeLogout(Subject subject) {
        RememberMeManager rmm = getRememberMeManager();
        if (rmm != null) {
            try {
        //清除cookie(重置cookie为默认值)
                rmm.onLogout(subject);
            } catch (Exception e) {
                if (log.isWarnEnabled()) {
                    String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
                            "] threw an exception during onLogout for subject with principals [" +
                            (subject != null ? subject.getPrincipals() : null) + "]";
                    log.warn(msg, e);
                }
            }
        }
    }

    /**
    用户登陆验证方法
    1.首先调用authenticate(token)验证当前用户登陆信息;
    2.登陆验证成功后,创建当前用户的subject且绑定到当前线程和把subject的状态信息保存到session中,方便以后重建subject
    **/
    public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo info;
        try {
        //调用父类AuthenticationSecurityManager的authenticate方法,验证用户是否登陆成功
            info = authenticate(token);
        } catch (AuthenticationException ae) {
            try {
            //如果验证失败,重置cookie为初始化值
                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
        }
        //创建subject
        Subject loggedIn = createSubject(token, info, subject);
    //设置唯一的principle到cookie中
        onSuccessfulLogin(token, info, loggedIn);

        return loggedIn;
    }

    protected void onSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
        rememberMeSuccessfulLogin(token, info, subject);
    }

    protected void onFailedLogin(AuthenticationToken token, AuthenticationException ae, Subject subject) {
        rememberMeFailedLogin(token, ae, subject);
    }

    protected void beforeLogout(Subject subject) {
        rememberMeLogout(subject);
    }

    protected SubjectContext copy(SubjectContext subjectContext) {
        return new DefaultSubjectContext(subjectContext);
    }


    public Subject createSubject(SubjectContext subjectContext) {
        //复制个subjectContext,不修改原来的subjectContext
        SubjectContext context = copy(subjectContext);

        //确保context已设置securityManager
        context = ensureSecurityManager(context);

        //确保context已设置session,如果不存在想办法获取已存在的session,然后设置进去
        context = resolveSession(context);

        //确保context已设置Principals,如果未设置则从rememberManager获取,然后设置
        context = resolvePrincipals(context);

    //调用subjectFactory创建subject
        Subject subject = doCreateSubject(context);

        //保存subject状态到session
        save(subject);

        return subject;
    }


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

    //调用subjectDAO保存subject状态
    protected void save(Subject subject) {
        this.subjectDAO.save(subject);
    }

    //调用subjectDAO删除subject状态
    protected void delete(Subject subject) {
        this.subjectDAO.delete(subject);
    }


    @SuppressWarnings({"unchecked"})
    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;
    }

    //确保session被设置到context
    @SuppressWarnings({"unchecked"})
    protected SubjectContext resolveSession(SubjectContext context) {
    //如果已经存在session,则直接返回context
        if (context.resolveSession() != null) {
            log.debug("Context already contains a session.  Returning.");
            return context;
        }
        try {

        //根据sessionKey从sessionManager获取session
            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;
    }

    //根据sessionKey从sessionManager获取session
    protected Session resolveContextSession(SubjectContext context) throws InvalidSessionException {
        SessionKey key = getSessionKey(context);
        if (key != null) {
            return getSession(key);
        }
        return null;
    }

    //获取sessionKey(SID)
    protected SessionKey getSessionKey(SubjectContext context) {
        Serializable sessionId = context.getSessionId();
        if (sessionId != null) {
            return new DefaultSessionKey(sessionId);
        }
        return null;
    }


    @SuppressWarnings({"unchecked"})
    protected SubjectContext resolvePrincipals(SubjectContext context) {

        PrincipalCollection principals = context.resolvePrincipals();

        if (CollectionUtils.isEmpty(principals)) {

        //从Remembered获取principals
            principals = getRememberedIdentity(context);

            if (!CollectionUtils.isEmpty(principals)) {

                context.setPrincipals(principals);

            } else {
                log.trace("No remembered identity found.  Returning original context.");
            }
        }

        return context;
    }


    protected SessionContext createSessionContext(SubjectContext subjectContext) {
        DefaultSessionContext sessionContext = new DefaultSessionContext();
        if (!CollectionUtils.isEmpty(subjectContext)) {
            sessionContext.putAll(subjectContext);
        }
        Serializable sessionId = subjectContext.getSessionId();
        if (sessionId != null) {
            sessionContext.setSessionId(sessionId);
        }
        String host = subjectContext.resolveHost();
        if (host != null) {
            sessionContext.setHost(host);
        }
        return sessionContext;
    }

    //用户退出方法
    public void logout(Subject subject) {

        if (subject == null) {
            throw new IllegalArgumentException("Subject method argument cannot be null.");
        }

    //在执行退出方法前,重置cookie为初始化值
        beforeLogout(subject);


        PrincipalCollection principals = subject.getPrincipals();
        if (principals != null && !principals.isEmpty()) {
            if (log.isDebugEnabled()) {
                log.debug("Logging out subject with primary principal {}", principals.getPrimaryPrincipal());
            }
        //调用验证器的onLogout方法,目前该方法主要是迭代AuthenticationListener的logout方法
            Authenticator authc = getAuthenticator();
            if (authc instanceof LogoutAware) {
                ((LogoutAware) authc).onLogout(principals);
            }
        }

        try {
            delete(subject);
        } catch (Exception e) {

        } finally {
            try {
        //设置session过期
                stopSession(subject);
            } catch (Exception e) {

            }
        }
    } 
    //设置session过期
    protected void stopSession(Subject subject) {
        Session s = subject.getSession(false);
        if (s != null) {
            s.stop();
        }
    }

    /**
     * Unbinds or removes the Subject's state from the application, typically called during {@link #logout}.
     * <p/>
     * This has been deprecated in Shiro 1.2 in favor of the {@link #delete(org.apache.shiro.subject.Subject) delete}
     * method.  The implementation has been updated to invoke that method.
     *
     * @param subject the subject to unbind from the application as it will no longer be used.
     * @deprecated in Shiro 1.2 in favor of {@link #delete(org.apache.shiro.subject.Subject)}
     */
    @Deprecated
    @SuppressWarnings({"UnusedDeclaration"})
    protected void unbind(Subject subject) {
        delete(subject);
    }

    //根据SubjectContext从RememberMeManager获取PrincipalCollection
    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;
    }
}

7.DefaultWebSecurityManager

//WebSecurityManager实现被使用在基于web的应用程序中或者需要http请求的应用程序中(如SOAP,http remoting, etc)
public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager {

    private static final Logger log = LoggerFactory.getLogger(DefaultWebSecurityManager.class);

    @Deprecated
    public static final String HTTP_SESSION_MODE = "http";
    @Deprecated
    public static final String NATIVE_SESSION_MODE = "native";

    /**
     * @deprecated as of 1.2.  This should NOT be used for anything other than determining if the sessionMode has changed.
     */
    @Deprecated
    private String sessionMode;

    public DefaultWebSecurityManager() {
        super();
    //设置SessionStorageEvaluator(评估Session是否需要存储,在无状态环境下可以设置为false,如Rest架构)到DefaultSubjectDAO
        ((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator());
        this.sessionMode = HTTP_SESSION_MODE;
    //初始化基于WEB的DefaultWebSubjectFactory
        setSubjectFactory(new DefaultWebSubjectFactory());
        setRememberMeManager(new CookieRememberMeManager());
    //默认是 基于servlet的session的sessionManaer,即不使用shiro自己管理的session
        setSessionManager(new ServletContainerSessionManager());
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public DefaultWebSecurityManager(Realm singleRealm) {
        this();
        setRealm(singleRealm);
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public DefaultWebSecurityManager(Collection<Realm> realms) {
        this();
        setRealms(realms);
    }

    @Override
    protected SubjectContext createSubjectContext() {
        return new DefaultWebSubjectContext();
    }

    @Override
    //since 1.2.1 for fixing SHIRO-350
    public void setSubjectDAO(SubjectDAO subjectDAO) {
        super.setSubjectDAO(subjectDAO);
    //设置sessionManager到DefaultSubjectDAO的SessionStorageEvaluator
        applySessionManagerToSessionStorageEvaluatorIfPossible();
    }

    //在sessionManager被设置后,设置sessionManager到DefaultSubjectDAO的SessionStorageEvaluator
    @Override
    protected void afterSessionManagerSet() {
        super.afterSessionManagerSet();
        applySessionManagerToSessionStorageEvaluatorIfPossible();
    }

    //设置sessionManager到DefaultSubjectDAO的SessionStorageEvaluator
    private void applySessionManagerToSessionStorageEvaluatorIfPossible() {
        SubjectDAO subjectDAO = getSubjectDAO();
        if (subjectDAO instanceof DefaultSubjectDAO) {
            SessionStorageEvaluator evaluator = ((DefaultSubjectDAO)subjectDAO).getSessionStorageEvaluator();
            if (evaluator instanceof DefaultWebSessionStorageEvaluator) {
                ((DefaultWebSessionStorageEvaluator)evaluator).setSessionManager(getSessionManager());
            }
        }
    }

    @Override
    protected SubjectContext copy(SubjectContext subjectContext) {
        if (subjectContext instanceof WebSubjectContext) {
            return new DefaultWebSubjectContext((WebSubjectContext) subjectContext);
        }
        return super.copy(subjectContext);
    }

    @SuppressWarnings({"UnusedDeclaration"})
    @Deprecated
    public String getSessionMode() {
        return sessionMode;
    }

    /**
     * @param sessionMode
     * @deprecated since 1.2
     */
    @Deprecated
    public void setSessionMode(String sessionMode) {
        log.warn("The 'sessionMode' property has been deprecated.  Please configure an appropriate WebSessionManager " +
                "instance instead of using this property.  This property/method will be removed in a later version.");
        String mode = sessionMode;
        if (mode == null) {
            throw new IllegalArgumentException("sessionMode argument cannot be null.");
        }
        mode = sessionMode.toLowerCase();
        if (!HTTP_SESSION_MODE.equals(mode) && !NATIVE_SESSION_MODE.equals(mode)) {
            String msg = "Invalid sessionMode [" + sessionMode + "].  Allowed values are " +
                    "public static final String constants in the " + getClass().getName() + " class: '"
                    + HTTP_SESSION_MODE + "' or '" + NATIVE_SESSION_MODE + "', with '" +
                    HTTP_SESSION_MODE + "' being the default.";
            throw new IllegalArgumentException(msg);
        }
        boolean recreate = this.sessionMode == null || !this.sessionMode.equals(mode);
        this.sessionMode = mode;
        if (recreate) {
            LifecycleUtils.destroy(getSessionManager());
            SessionManager sessionManager = createSessionManager(mode);
            this.setInternalSessionManager(sessionManager);
        }
    }

    @Override
    public void setSessionManager(SessionManager sessionManager) {
        this.sessionMode = null;
        if (sessionManager != null && !(sessionManager instanceof WebSessionManager)) {
            if (log.isWarnEnabled()) {
                String msg = "The " + getClass().getName() + " implementation expects SessionManager instances " +
                        "that implement the " + WebSessionManager.class.getName() + " interface.  The " +
                        "configured instance is of type [" + sessionManager.getClass().getName() + "] which does not " +
                        "implement this interface..  This may cause unexpected behavior.";
                log.warn(msg);
            }
        }
        setInternalSessionManager(sessionManager);
    }

    /**
     * @param sessionManager
     * @since 1.2
     */
    private void setInternalSessionManager(SessionManager sessionManager) {
        super.setSessionManager(sessionManager);
    }

    //判断是否是使用httpSession
    public boolean isHttpSessionMode() {
        SessionManager sessionManager = getSessionManager();
        return sessionManager instanceof WebSessionManager && ((WebSessionManager)sessionManager).isServletContainerSessions();
    }

    protected SessionManager createSessionManager(String sessionMode) {
        if (sessionMode == null || !sessionMode.equalsIgnoreCase(NATIVE_SESSION_MODE)) {
            log.info("{} mode - enabling ServletContainerSessionManager (HTTP-only Sessions)", HTTP_SESSION_MODE);
            return new ServletContainerSessionManager();
        } else {
            log.info("{} mode - enabling DefaultWebSessionManager (non-HTTP and HTTP Sessions)", NATIVE_SESSION_MODE);
            return new DefaultWebSessionManager();
        }
    }

    @Override
    protected SessionContext createSessionContext(SubjectContext subjectContext) {
        SessionContext sessionContext = super.createSessionContext(subjectContext);
        if (subjectContext instanceof WebSubjectContext) {
            WebSubjectContext wsc = (WebSubjectContext) subjectContext;
            ServletRequest request = wsc.resolveServletRequest();
            ServletResponse response = wsc.resolveServletResponse();
            DefaultWebSessionContext webSessionContext = new DefaultWebSessionContext(sessionContext);
            if (request != null) {
                webSessionContext.setServletRequest(request);
            }
            if (response != null) {
                webSessionContext.setServletResponse(response);
            }

            sessionContext = webSessionContext;
        }
        return sessionContext;
    }

    @Override
    protected SessionKey getSessionKey(SubjectContext context) {
        if (WebUtils.isWeb(context)) {
            Serializable sessionId = context.getSessionId();
            ServletRequest request = WebUtils.getRequest(context);
            ServletResponse response = WebUtils.getResponse(context);
            return new WebSessionKey(sessionId, request, response);
        } else {
            return super.getSessionKey(context);

        }
    }

    @Override
    protected void beforeLogout(Subject subject) {
        super.beforeLogout(subject);
        removeRequestIdentity(subject);
    }

    protected void removeRequestIdentity(Subject subject) {
        if (subject instanceof WebSubject) {
            WebSubject webSubject = (WebSubject) subject;
            ServletRequest request = webSubject.getServletRequest();
            if (request != null) {
                request.setAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY, Boolean.TRUE);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值