Spring Shiro基础组件 SecurityManager

相关阅读

简介

为应用程序中所有Subject执行所有安全操作;
继承AuthenticatorAuthorizerSessionManager接口,并额外提供支持Subject行为的方法;

核心方法

/**
 * 登录
 * 成功则返回更新后的反映身份验证后的Subject实例,失败则抛出AuthenticationException
 * 首选方式是subject.login(AuthenticationToken)
 */
Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;

/**
 * 登出
 * 首选方式是subject.login()
 */
void logout(Subject subject);

/**
 * 根据指定上下文数据创建Subject实例
 */
Subject createSubject(SubjectContext context);

实现子类

public interface SecurityManager extends Authenticator, Authorizer, SessionManager
    public abstract class CachingSecurityManager implements SecurityManager, Destroyable, CacheManagerAware, EventBusAware
        public abstract class RealmSecurityManager extends CachingSecurityManager
            public abstract class AuthenticatingSecurityManager extends RealmSecurityManager
                public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager
                    public abstract class SessionsSecurityManager extends AuthorizingSecurityManager
                        public class DefaultSecurityManager extends SessionsSecurityManager
                            public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager
    public interface WebSecurityManager extends SecurityManager
        public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager

CachingSecurityManager

简介

基于SecurityManager接口,提供日志和缓存的支持;
所有的SecurityManager接口的方法由子类实现;

核心方法

// 缓存管理器
private CacheManager cacheManager;
// 事件总线
private EventBus eventBus;

/**
 * 构造方法
 */
public CachingSecurityManager() {
    // 默认使用DefaultEventBus
    //use a default event bus:
    setEventBus(new DefaultEventBus());
}

/**
 * 模板回调方法,通知子类缓存管理器已设置
 */
protected void afterCacheManagerSet() {
    applyEventBusToCacheManager();
}

/**
 * 模板回调方法,通知子类事件总线已设置
 */
protected void afterEventBusSet() {
    applyEventBusToCacheManager();
}

/**
 * 将事件总线应用到缓存管理器
 */
protected void applyEventBusToCacheManager() {
    if (this.eventBus != null && this.cacheManager != null && this.cacheManager instanceof EventBusAware) {
        ((EventBusAware)this.cacheManager).setEventBus(this.eventBus);
    }
}

/**
 * 销毁资源
 */
public void destroy() {
    LifecycleUtils.destroy(getCacheManager());
    this.cacheManager = null;
    LifecycleUtils.destroy(getEventBus());
    this.eventBus = new DefaultEventBus();
}

RealmSecurityManager

简介

基于SecurityManager接口,提供Realm集合的支持;
所有的SecurityManager接口的方法由子类实现;

核心方法

// 用于鉴权、授权的realm集合
private Collection<Realm> realms;

/**
 * 模板回调方法,通知realm集合已设置
 */
protected void afterRealmsSet() {
    applyCacheManagerToRealms();
    applyEventBusToRealms();
}

/**
 * 将缓存管理器应用到realm集合
 */
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);
            }
        }
    }
}

/**
 * 将事件总线应用到realm集合
 */
protected void applyEventBusToRealms() {
    EventBus eventBus = getEventBus();
    Collection<Realm> realms = getRealms();
    if (eventBus != null && realms != null && !realms.isEmpty()) {
        for(Realm realm : realms) {
            if (realm instanceof EventBusAware) {
                ((EventBusAware)realm).setEventBus(eventBus);
            }
        }
    }
}

/**
 * 模板回调方法,通知子类缓存管理器已设置
 */
protected void afterCacheManagerSet() {
    // 调用父类方法完成父类回调
    super.afterCacheManagerSet();
    applyCacheManagerToRealms();
}

/**
 * 模板回调方法,通知子类事件总线已设置
 */
@Override
protected void afterEventBusSet() {
    // 调用父类方法完成父类回调
    super.afterEventBusSet();
    applyEventBusToRealms();
}

/**
 * 销毁资源
 */
public void destroy() {
    LifecycleUtils.destroy(getRealms());
    this.realms = null;
    // 调用父类方法销毁父类资源
    super.destroy();
}

AuthenticatingSecurityManager

简介

利用内部包装的Authenticator实例实现SecurityManagerAuthenticator接口的所有方法;其他方法由子类实现;
为了尽可能减少配置,Shiro在实例化时为所有依赖项创建合适的默认实例;

核心方法

// 内部包装的Authenticator实例
private Authenticator authenticator;

/**
 * 构造方法
 */
public AuthenticatingSecurityManager() {
    super();
    // 默认使用ModularRealmAuthenticator
    this.authenticator = new ModularRealmAuthenticator();
}

/**
 * 模板回调方法,通知realm集合已设置
 */
protected void afterRealmsSet() {
    super.afterRealmsSet();
    if (this.authenticator instanceof ModularRealmAuthenticator) {
        // 将realm集合应用到ModularRealmAuthenticator
        ((ModularRealmAuthenticator) this.authenticator).setRealms(getRealms());
    }
}

/**
 * 基于提交的AuthenticationToken来鉴权
 */
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
    // 委托内部包装的Authenticator实例实现鉴权
    return this.authenticator.authenticate(token);
}

/**
 * 销毁资源
 */
public void destroy() {
    LifecycleUtils.destroy(getAuthenticator());
    this.authenticator = null;
    // 调用父类方法销毁父类资源
    super.destroy();
}

AuthorizingSecurityManager

简介

利用内部包装的Authorizer实例实现SecurityManagerAuthorizer接口的所有方法;其他方法由子类实现;
为了尽可能减少配置,Shiro在实例化时为所有依赖项创建合适的默认实例;

核心方法

// 内部包装的Authorizer实例
private Authorizer authorizer;

/**
 * 构造方法
 */
public AuthorizingSecurityManager() {
    super();
    // 默认使用ModularRealmAuthorizer
    this.authorizer = new ModularRealmAuthorizer();
}

/**
 * 模板回调方法,通知realm集合已设置
 */
protected void afterRealmsSet() {
    super.afterRealmsSet();
    if (this.authorizer instanceof ModularRealmAuthorizer) {
        // 将realm集合应用到ModularRealmAuthorizer
        ((ModularRealmAuthorizer) this.authorizer).setRealms(getRealms());
    }
}

/**
 * 销毁资源
 */
public void destroy() {
    LifecycleUtils.destroy(getAuthorizer());
    this.authorizer = null;
    // 调用父类方法销毁父类资源
    super.destroy();
}

/**
 * Authorizer接口的方法皆委托内部包装的Authorizer实例实现
 */
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);
}

SessionsSecurityManager

简介

利用内部包装的SessionManager实例实现SecurityManagerSessionManager接口的所有方法;其他方法由子类实现;
为了尽可能减少配置,Shiro在实例化时为所有依赖项创建合适的默认实例;

核心方法

// 内部包装的SessionManager实例
private SessionManager sessionManager;

/**
 * 构造方法
 */
public SessionsSecurityManager() {
    super();
    // 默认使用DefaultSessionManager
    this.sessionManager = new DefaultSessionManager();
    applyCacheManagerToSessionManager();
}

/**
 * 模板回调方法,通知sessionManager已设置
 */
protected void afterSessionManagerSet() {
    applyCacheManagerToSessionManager();
    applyEventBusToSessionManager();
}

/**
 * 模板回调方法,通知子类缓存管理器已设置
 */
@Override
protected void afterCacheManagerSet() {
    super.afterCacheManagerSet();
    applyCacheManagerToSessionManager();
}

/**
 * 模板回调方法,通知子类事件总线已设置
 */
@Override
protected void afterEventBusSet() {
    super.afterEventBusSet();
    applyEventBusToSessionManager();
}

/**
 * 将缓存管理器应用到会话管理器
 */
protected void applyCacheManagerToSessionManager() {
    if (this.sessionManager instanceof CacheManagerAware) {
        ((CacheManagerAware) this.sessionManager).setCacheManager(getCacheManager());
    }
}

/**
 * 将事件总线应用到会话管理器
 */
protected void applyEventBusToSessionManager() {
    EventBus eventBus = getEventBus();
    if (eventBus != null && this.sessionManager instanceof EventBusAware) {
        ((EventBusAware)this.sessionManager).setEventBus(eventBus);
    }
}

/**
 * 根据上下文初始化数据创建新会话
 */
public Session start(SessionContext context) throws AuthorizationException {
    return this.sessionManager.start(context);
}

/**
 * 根据会话ID查找会话
 * 如果找到但会话无效(停止或过期),则抛出SessionException
 */
public Session getSession(SessionKey key) throws SessionException {
    return this.sessionManager.getSession(key);
}

/**
 * 销毁资源
 */
public void destroy() {
    LifecycleUtils.destroy(getSessionManager());
    this.sessionManager = null;
    // 调用父类方法销毁父类资源
    super.destroy();
}

DefaultSecurityManager

简介

基于Realm集合的SecurityManager的默认实现,通过父类委托AuthenticatorAuthorizerSessionManager实例分别实现AuthenticatorAuthorizerSessionManager接口;
为了尽可能减少配置,Shiro在实例化时为所有依赖项创建合适的默认实例, 除了必要的Realm集合;
Realm通常与应用程序的数据模型进行交互,特定于应用程序;
支持配置RememberMeManager以进行登录/登出操作,默认不创建,需要通过setRememberMeManager()指定;

核心方法

protected RememberMeManager rememberMeManager;
protected SubjectDAO subjectDAO;
protected SubjectFactory subjectFactory;

/**
 * 构造方法
 */
public DefaultSecurityManager() {
    super();
    this.subjectFactory = new DefaultSubjectFactory();
    this.subjectDAO = new DefaultSubjectDAO();
}

/**
 * 创建Subject上下文
 */
protected SubjectContext createSubjectContext() {
    // 默认使用DefaultSubjectContext
    return new DefaultSubjectContext();
}

/**
 * 创建Subject
 */
protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {
    // 创建Subject上下文
    SubjectContext context = createSubjectContext();
    // 设置Subject上下文数据
    context.setAuthenticated(true);
    context.setAuthenticationToken(token);
    context.setAuthenticationInfo(info);
    context.setSecurityManager(this);
    if (existing != null) {
        context.setSubject(existing);
    }
    // 根据上下文数据创建Subject实例
    return createSubject(context);
}

/**
 * 记住登录成功
 */
protected void rememberMeSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
    RememberMeManager rmm = getRememberMeManager();
    if (rmm != null) {
        try {
            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 {
            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 {
            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);
            }
        }
    }
}

/**
 * 登录
 */
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
    }

    // 鉴权成功后则创建表示验证后账户的Subject
    Subject loggedIn = createSubject(token, info, subject);

    // 登录成功处理
    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);
}

/**
 * 拷贝Subject上下文
 */
protected SubjectContext copy(SubjectContext subjectContext) {
    return new DefaultSubjectContext(subjectContext);
}

/**
 * 根据指定上下文数据创建Subject实例
 */
public Subject createSubject(SubjectContext subjectContext) {
    // 拷贝原Subject上下文,后续操作基于备份,而不会修改入参
    //create a copy so we don't modify the argument's backing map:
    SubjectContext context = copy(subjectContext);

    // 确保上下文拥有SecurityManager实例
    //ensure that the context has a SecurityManager instance, and if not, add one:
    context = ensureSecurityManager(context);

    // 解析和上下文相关联的Session实例
    //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);

    // 解析和上下文相关的PrincipalCollection
    //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 subject = doCreateSubject(context);

    // 保存Subject
    //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;
}

/**
 * 创建Subject
 */
protected Subject doCreateSubject(SubjectContext context) {
    // 借助SubjectFactory创建Subject
    return getSubjectFactory().createSubject(context);
}

/**
 * 保存Subject
 */
protected void save(Subject subject) {
    this.subjectDAO.save(subject);
}

/**
 * 删除Subject
 */
protected void delete(Subject subject) {
    this.subjectDAO.delete(subject);
}

/**
 * 确保上下文拥有SecurityManager实例
 */
protected SubjectContext ensureSecurityManager(SubjectContext context) {
    if (context.resolveSecurityManager() != null) {
        // SecurityManager实例已存在则直接返回
        log.trace("Context already contains a SecurityManager instance.  Returning.");
        return context;
    }
    log.trace("No SecurityManager found in context.  Adding self reference.");
    // 设置本实例为上下文的SecurityManager实例
    context.setSecurityManager(this);
    return context;
}

/**
 * 解析和上下文相关联的Session实例
 */
protected SubjectContext resolveSession(SubjectContext context) {
    if (context.resolveSession() != null) {
        // 已存在Session实例则直接返回
        log.debug("Context already contains a session.  Returning.");
        return context;
    }
    try {
        // 根据上下文解析相关联的Session实例
        //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) {
            // 若Session实例存在,则设置该Session实例
            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;
}

/**
 * 根据上下文解析相关联的Session实例
 */
protected Session resolveContextSession(SubjectContext context) throws InvalidSessionException {
    // 从上下文中获取Session key
    SessionKey key = getSessionKey(context);
    if (key != null) {
        // 若Session key存在,则根据key获取Session实例
        return getSession(key);
    }
    // 若Session key不存在,则直接返回null
    return null;
}

/**
 * 从上下文中获取Session Key
 */
protected SessionKey getSessionKey(SubjectContext context) {
    // 从上下文中获取Session id
    Serializable sessionId = context.getSessionId();
    if (sessionId != null) {
        // 若Session id存在,则包装为DefaultSessionKey
        return new DefaultSessionKey(sessionId);
    }
    // 不存在Session id,则直接返回null
    return null;
}

/**
 * 解析和上下文相关的PrincipalCollection
 */
protected SubjectContext resolvePrincipals(SubjectContext context) {
    // 从上下文获取principalCollection
    PrincipalCollection principals = context.resolvePrincipals();

    if (isEmpty(principals)) {
        log.trace("No identity (PrincipalCollection) found in the context.  Looking for a remembered identity.");

        // 若principalCollection为空,则获取remembered信息
        principals = getRememberedIdentity(context);

        if (!isEmpty(principals)) {
            log.debug("Found remembered PrincipalCollection.  Adding to the context to be used " +
                    "for subject construction by the SubjectFactory.");

            // remembered信息存在,则设置
            context.setPrincipals(principals);

            // The following call was removed (commented out) in Shiro 1.2 because it uses the session as an
            // implementation strategy.  Session use for Shiro's own needs should be controlled in a single place
            // to be more manageable for end-users: there are a number of stateless (e.g. REST) applications that
            // use Shiro that need to ensure that sessions are only used when desirable.  If Shiro's internal
            // implementations used Subject sessions (setting attributes) whenever we wanted, it would be much
            // harder for end-users to control when/where that occurs.
            //
            // Because of this, the SubjectDAO was created as the single point of control, and session state logic
            // has been moved to the DefaultSubjectDAO implementation.


            // Removed in Shiro 1.2.  SHIRO-157 is still satisfied by the new DefaultSubjectDAO implementation
            // introduced in 1.2
            // Satisfies SHIRO-157:
            // bindPrincipalsToSession(principals, context);

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

    return context;
}

/**
 * 根据Subject上下文创建Session上下文
 */
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) {

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

    // 登出前处理
    beforeLogout(subject);

    PrincipalCollection principals = subject.getPrincipals();
    if (principals != null && !principals.isEmpty()) {
        if (log.isDebugEnabled()) {
            log.debug("Logging out subject with primary principal {}", principals.getPrimaryPrincipal());
        }
        Authenticator authc = getAuthenticator();
        if (authc instanceof LogoutAware) {
            // 通知Authenticator登出事件
            ((LogoutAware) authc).onLogout(principals);
        }
    }

    try {
        // 删除Subject
        delete(subject);
    } catch (Exception e) {
        if (log.isDebugEnabled()) {
            String msg = "Unable to cleanly unbind Subject.  Ignoring (logging out).";
            log.debug(msg, e);
        }
    } finally {
        try {
            // 停止会话
            stopSession(subject);
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                String msg = "Unable to cleanly stop Session for Subject [" + subject.getPrincipal() + "] " +
                        "Ignoring (logging out).";
                log.debug(msg, e);
            }
        }
    }
}

/**
 * 停止会话
 */
protected void stopSession(Subject subject) {
    Session s = subject.getSession(false);
    if (s != null) {
        s.stop();
    }
}

/**
 * 根据Subject上下文获取已记录的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;
}

WebSecurityManager

简介

可以用于Web应用程序的SecurityManager

核心方法

/**
 * 是否使用HttpSession
 */
boolean isHttpSessionMode();

DefaultWebSecurityManager

简介

在Web应用程序或任何需要HTTP连接(SOAP、http远程处理等)的应用程序中使用的WebSecurityManager接口的默认实现;

核心方法

/**
 * 构造方法
 */
public DefaultWebSecurityManager() {
    super();
    DefaultWebSessionStorageEvaluator webEvalutator = new DefaultWebSessionStorageEvaluator();  
    ((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(webEvalutator);
    this.sessionMode = HTTP_SESSION_MODE;
    // 默认使用DefaultWebSubjectFactory
    setSubjectFactory(new DefaultWebSubjectFactory());
    // 默认使用CookieRememberedMeManager
    setRememberMeManager(new CookieRememberMeManager());
    // 默认使用ServletContainerSessionManager
    setSessionManager(new ServletContainerSessionManager());
    webEvalutator.setSessionManager(getSessionManager());
}

/**
 * 创建Subject上下文
 */
protected SubjectContext createSubjectContext() {
    return new DefaultWebSubjectContext();
}

/**
 * 设置SubjectDao
 */
public void setSubjectDAO(SubjectDAO subjectDAO) {
    super.setSubjectDAO(subjectDAO);
    applySessionManagerToSessionStorageEvaluatorIfPossible();
}

/**
 * 模板回调方法,通知sessionManager已设置
 */
@Override
protected void afterSessionManagerSet() {
    super.afterSessionManagerSet();
    applySessionManagerToSessionStorageEvaluatorIfPossible();
}

/**
 * 将Session管理器应用到SessionStorageEvaluator
 */
private void applySessionManagerToSessionStorageEvaluatorIfPossible() {
    SubjectDAO subjectDAO = getSubjectDAO();
    if (subjectDAO instanceof DefaultSubjectDAO) {
        SessionStorageEvaluator evaluator = ((DefaultSubjectDAO)subjectDAO).getSessionStorageEvaluator();
        if (evaluator instanceof DefaultWebSessionStorageEvaluator) {
            ((DefaultWebSessionStorageEvaluator)evaluator).setSessionManager(getSessionManager());
        }
    }
}

/**
 * 拷贝Subject上下文
 */
@Override
protected SubjectContext copy(SubjectContext subjectContext) {
    if (subjectContext instanceof WebSubjectContext) {
        return new DefaultWebSubjectContext((WebSubjectContext) subjectContext);
    }
    return super.copy(subjectContext);
}

/**
 * 设置Session管理器
 */
@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);
}

/**
 * 设置内部的Session管理器实例
 */
private void setInternalSessionManager(SessionManager sessionManager) {
    super.setSessionManager(sessionManager);
}

/**
 * 是否是HttpSession
 */
public boolean isHttpSessionMode() {
    SessionManager sessionManager = getSessionManager();
    return sessionManager instanceof WebSessionManager && ((WebSessionManager)sessionManager).isServletContainerSessions();
}

/**
 * 创建Session管理器
 */
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();
    }
}

/**
 * 根据Subject上下文创建Session上下文
 */
@Override
protected SessionContext createSessionContext(SubjectContext subjectContext) {
    SessionContext sessionContext = super.createSessionContext(subjectContext);
    if (subjectContext instanceof WebSubjectContext) {
        // 添加Request和Response信息
        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;
}

/**
 * 从上下文中获取Session Key
 */
@Override
protected SessionKey getSessionKey(SubjectContext context) {
    if (WebUtils.isWeb(context)) {
        // 如果兼容Http,则返回WebSessionKey
        Serializable sessionId = context.getSessionId();
        ServletRequest request = WebUtils.getRequest(context);
        ServletResponse response = WebUtils.getResponse(context);
        return new WebSessionKey(sessionId, request, response);
    } else {
        // 否则使用父类方法获取Session key
        return super.getSessionKey(context);
    }
}

/**
 * 登出前处理
 */
@Override
protected void beforeLogout(Subject subject) {
    // 调用父类方法进行登出前处理
    super.beforeLogout(subject);
    // 清除Request中身份信息
    removeRequestIdentity(subject);
}

/**
 * 清除Request中身份信息
 */
protected void removeRequestIdentity(Subject subject) {
    if (subject instanceof WebSubject) {
        WebSubject webSubject = (WebSubject) subject;
        ServletRequest request = webSubject.getServletRequest();
        if (request != null) {
            // 设置IDENTITY_REMOVED_KEY属性为TRUE
            request.setAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY, Boolean.TRUE);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值