1. 我们知道SecurityManager安全管理器,是Shiro的核心,现在就看一下这个
public interface SecurityManager extends Authenticator, Authorizer, SessionManager {
//登录方法
Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;
//注销方法
void logout(Subject subject);
//创建subject
Subject createSubject(SubjectContext context);
}
初始的安全管理器接口有三个方法,并且实现了三个接口,分别来看一下,这三个接口
1.1 Authenticator(认证器) ,用户登录时候会调用
public interface Authenticator {
//初始的认证方法,入参是一个令牌对象,返回值是一个包装好的身份信息
public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException;
}
1.2 Authorizer(授权器) 检查是否具有相关的权限.这个接口定义的都是检查权限和角色的方法
1.3 SessionManager(会话管理器) 这个后面会有详细的解释
2. Securitymanager的继承体系
与spring整合的默认安全管理器就是图中标注的那个,一般如果不自己定义的话,就会使用这个东西
很有意思的集成体系,每次继承都实现一些接口,或者实现一些特色的功能,这个学习到了
2.1 CacheSecurityManager 从名字就可以知道它应该是注入了缓存相关的东西
2.1.1 定义
public abstract class CachingSecurityManager implements SecurityManager, Destroyable, CacheManagerAware, EventBusAware
实现了四个接口,除了第一个,后面三个都是简单的,暂时不做处理
2.1.2 属性
//注入的缓存管理器
private CacheManager cacheManager;
//不知道这个鬼是什么作用,感觉想那种can总线结构
private EventBus eventBus;
2.1.3 构造
public CachingSecurityManager() {
//注入了一个默认的eventBus
setEventBus(new DefaultEventBus());
}
2.1.4 一些有意思的方法
//这个方法就是将默认eventBus注入cachemanager中.这个写法后面还有用到
//这个方法会在 setCacheManager(CacheManager cacheManager) 里面执行
protected void applyEventBusToCacheManager() {
if (this.eventBus != null && this.cacheManager != null && this.cacheManager instanceof EventBusAware) {
((EventBusAware)this.cacheManager).setEventBus(this.eventBus);
}
}
2.2 RealmSecurityManager 这个抽象类实现了Realm(数据源)先关的功能
2.2.1 定义
//没有实现任何接口,只做了继承
public abstract class RealmSecurityManager extends CachingSecurityManager{}
2.2.2 属性
//注入了数据源的集合
private Collection<Realm> realms;
2.2.3 构造 //只有一个空实现
2.2.4 一些方法
//这个方法就是将缓存管理器,eventbus注入到realm中,这个方法在setRealms(Collection<Realm> realms)调用
//realm需要实现CachemanagerAware接口,才能注入缓存管理器
protected void afterRealmsSet() {
applyCacheManagerToRealms();
applyEventBusToRealms();
}
//这个方法定义了默认的realm的实现是一个arrayList集合
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);
}
2.3 AuthenticatingSecurityManager 这个方法实现了认证的部分功能
2.3.1 定义
//只是单纯的继承,没有实现任何借口
public abstract class AuthenticatingSecurityManager extends RealmSecurityManager{}
2.3.2 属性
private Authenticator authenticator;AuthorizingSecurityManager
2.3.3 构造
//注入了一个认证器,这个认证器具有默认的实现ModularRealmAuthenticator
public AuthenticatingSecurityManager() {
super();
this.authenticator = new ModularRealmAuthenticator();
}
2.3.4 一些方法
//调用完父类的方法后,这个方法会将所有的数据源Realms集合注入到定义的authenticator中,注意这个必须是ModularRealmAuthenticator子类
protected void afterRealmsSet() {
super.afterRealmsSet();
if (this.authenticator instanceof ModularRealmAuthenticator) {
((ModularRealmAuthenticator) this.authenticator).setRealms(getRealms());
}
}
//当调用这个方法后,就会调用默认的认证器中的认证方法
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
return this.authenticator.authenticate(token);
}
2.4 AuthorizingSecurityManager 完成授权部分功能
2.4.1 定义,只是单纯的继承,没有实现任何接口
2.4.2 属性 单纯出入了一个授权器
private Authorizer authorizer;
2.4.3 构造
// 注意这个授权器是有默认实现的 ,而且和上面那个类很类似,猛地一看差不多,其实不一样
public AuthorizingSecurityManager() {
super();
this.authorizer = new ModularRealmAuthorizer();
}
2.4.4 一些方法//和上面的类似,将所有的Realms注入到了授权器中,这个授权器必须是ModularRealmAuthorizer的子类
protected void afterRealmsSet() {
super.afterRealmsSet();
if (this.authorizer instanceof ModularRealmAuthorizer) {
((ModularRealmAuthorizer) this.authorizer).setRealms(getRealms());
}
}
//调用这个类的方法,会调用注入的授权器中相应的方法
public boolean isPermitted(PrincipalCollection principals, String permissionString) {
return this.authorizer.isPermitted(principals, permissionString);
}
2.5 SessionsSecurityManager 注入了会话管理器
2.5.1 定义 单纯的继承,没有实现
2.5.2 属性 注入 会话管理器
private SessionManager sessionManager;
2.5.3 构造
// 注入了一个默认的会话管理器,并且将缓存管理器注入会话管理器中,要求,sessionManager必须实现了CacheManagerAware的接口
public SessionsSecurityManager() {
super();
this.sessionManager = new DefaultSessionManager();
applyCacheManagerToSessionManager();
}
2.6 DefaultSecurityManager 默认非web环境的安全管理器
2.6.1 定义 单纯的继承,没有实现
2.6.2 属性
protected RememberMeManager rememberMeManager;
protected SubjectDAO subjectDAO;
protected SubjectFactory subjectFactory;
2.6.3 构造//注意注入了默认的subjectFactory()和subjectDao
public DefaultSecurityManager() {
super();
this.subjectFactory = new DefaultSubjectFactory();
this.subjectDAO = new DefaultSubjectDAO();
}
2.6.4 一些方法 //根据subjectContext以及令牌token,认证信息info,创建subject
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);
}
//下面这三个,就是关于RememberMe功能,如果这个功能为true,那么就会执行相应的操作
protected void rememberMeSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
RememberMeManager rmm = getRememberMeManager();
if (rmm != null) {
try {
rmm.onSuccessfulLogin(subject, token, info);
} catch (Exception e) {
}
}
} else {
}
}
}
protected void rememberMeFailedLogin(AuthenticationToken token, AuthenticationException ex, Subject subject) {
RememberMeManager rmm = getRememberMeManager();
if (rmm != null) {
try {
rmm.onFailedLogin(subject, token, ex);
} catch (Exception e) {
}
}
}
}
protected void rememberMeLogout(Subject subject) {
RememberMeManager rmm = getRememberMeManager();
if (rmm != null) {
try {
rmm.onLogout(subject);
} catch (Exception 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) {
...
}
}
throw ae; //propagate
}
Subject loggedIn = createSubject(token, info, subject);
onSuccessfulLogin(token, info, loggedIn);
return loggedIn;
}
//这是注销方法,
public void logout(Subject subject) {
if (subject == null) {
throw new IllegalArgumentException("Subject method argument cannot be null.");
}
//注销remeberme操作
beforeLogout(subject);
PrincipalCollection principals = subject.getPrincipals();
if (principals != null && !principals.isEmpty()) {
Authenticator authc = getAuthenticator();
if (authc instanceof LogoutAware) {
//我们知道authc是有一个默认值的,这个默认值是实现了LogoutAware这个接口的
((LogoutAware) authc).onLogout(principals);
}
}
try {
delete(subject);
} catch (Exception e) {
}
} finally {
try {
stopSession(subject);
} catch (Exception e) {
}
}
}
}
2.7 DefaultWebSecurityManager 默认的继承web层次的安全管理器
2.7.1 定义 除了继承之外,还实现了一个接口,这个接口的功能就是判断当前是否是web环境
public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager{}
2.7.5 属性
只有三个过期的属性,自1.2之后就不应使用了
@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;
2.7.3 构造
public DefaultWebSecurityManager() {
super();
((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator());
this.sessionMode = HTTP_SESSION_MODE;
setSubjectFactory(new DefaultWebSubjectFactory());
setRememberMeManager(new CookieRememberMeManager());
setSessionManager(new ServletContainerSessionManager());
}
重置了subjectFactory,rememberMeManager,SessionManager这三个默认值
2.7.4 一些方法
//这个就是现在判断是不是web环境的,方法在构造中已经重置了sessionmMnager为ServletContainerSessionManager,这个类的isSer..()方法返回就是true
public boolean isHttpSessionMode() {
SessionManager sessionManager = getSessionManager();
return sessionManager instanceof WebSessionManager && ((WebSessionManager)sessionManager).isServletContainerSessions();
}