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 realms;
public void setRealm(Realm realm) {
if (realm == null) {
throw new IllegalArgumentException("Realm argument cannot be null");
}
Collection realms = new ArrayList(1);
realms.add(realm);
setRealms(realms);
}
public void setRealms(Collection 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 getRealms() {
return realms;
}
//设置cacheManager到Realm中,因为Realm是数据处理组件,当它从数据库中加载数据且得到正确的验证后,可以缓存到cacheManager,来提供性能。在shiro里,AuthorizationInfo(授权数据)和AuthenticationInfo(用户基本账户密码)都被缓存到cacheManager在验证成功后
protected void applyCacheManagerToRealms() {
CacheManager cacheManager = getCacheManager();
Collection 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 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 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 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 roleIdentifiers) {
return this.authorizer.hasRoles(principals, roleIdentifiers);
}
public boolean hasAllRoles(PrincipalCollection principals, Collection 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 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 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}.
*
* 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 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);
}
}
}
}