工具类
SecurityUtils:提供给开发者使用的工具类,内部持有Subject、SecurityManager类实例对象。
public static Subject getSubject();
public static SecurityManager getSecurityManager();
Subject:用户通常通过此类与Shiro进行交互。持有securityManager、subjectContext等的引用。提供login 、logout、isAuthenticaed 、isPermited 等方法
public interface Subject {
void login(AuthenticationToken var1) throws AuthenticationException;
void logout();
Object getPrincipal();
Session getSession(boolean var1);
boolean isAuthenticated();
boolean isPermitted(String var1);
boolean hasRole(String var1);
<V> V execute(Callable<V> var1) throws ExecutionException;
Runnable associateWith(Runnable var1);
void runAs(PrincipalCollection var1) throws NullPointerException, IllegalStateException;
PrincipalCollection releaseRunAs();
......
用于封装账户权限等信息的JavaBean POJO
- principal:账号。类同登录时的用户名
- credential:凭据。类同登录时的密码
- AuthenticationToken:用于封装用户在尝试身份认证时提交的 账号和凭据的 JavaBean,即 principal + credential。
AuthenticationToken 的常见实现有用户名/密码对、X.509证书、PGP密钥或您可以想到的任何其他内容。 - AuthenticationInfo:用于封装一个已经认证通过的账户和凭证的用户的信息的 JavaBean。
- AuthorizationInfo:用于封装一个用户的权限信息的 JavaBean。
- Account :同时继承了 Authenticaiton 、Authorization 两个接口
AuthenticationToken
用于封装用户在尝试身份认证时提交的 账号和凭据的 JavaBean,即 principal + credential。
只定义了两个接口方法:
Object getPrincipal();
Object getCredential();
由于应用程序以不同的方式表示用户数据和凭证,因此 AuthenticationToken 接口的实现是特定于应用程序的。您可以随意获取用户的主体和凭证(如web表单、Swing表单、指纹识别等),然后以AuthenticationToken接口的实现类对象形式将其提交给Shiro框架。
如果您的应用程序的身份验证过程是基于用户名/密码的(与大多数情况类似),那么不要自己实现这个接口,而是查看UsernamePasswordToken类,因为它可能足以满足您的需要。
如果需要RemenberMe服务,则可以通过继承RemenberMeService接口的实现类RememberMeAuthenticationToken来实现。继承了这个类的AuthenticationToken的实现类,就直接能提供RemenberMe功能。(UsernamePasswordToken已经实现了该接口)。
如果您熟悉JAAS,AuthenticationToken将取代javax.security.auth.callback的概念。回调,并定义有意义的行为(回调只是一个标记接口,没有什么用处)。我们还认为名称AuthenticationToken在登录框架中更准确地反映了它的真正用途,而回调则不那么明显。
现在的web应用通常是多平台支撑的,因此通常是在拦截到登录请求时会提取登录表单提交来的 username 和 password 自动创建 UsernamePasswordToken。登录验证成功后,服务器返回给客户端一个token。其后客户端向服务器发送请求时,都是提交此 token 作为认证用的数据,而其后的业务请求则提交 自定义实现的 AuthenticationToken 接口的子类。
AuthenticationInfo
一个这个类对象表示一个已经认证通过的账户和凭证的用户的信息。
AuthenticationInfo 表示仅与身份验证/登录过程相关的主体(又名用户)存储的帐户信息。
了解此接口和 AuthenticationToken 接口之间的区别非常重要。
AuthenticationInfo 实现表示已验证和存储的帐户数据,而 AuthenticationToken 表示为任何给定登录尝试提交的数据(可能与已验证和已存储的帐户AuthenticationInfo匹配,也可能不匹配),由于身份验证(认证)行为与授权(访问控制)正交,因此该接口(AuthenticationToken)仅用于表示Shiro在身份验证尝试期间所需的帐户数据。
Shiro还有一个并行的 AuthorizationInfo - 授权信息接口,用于在授权过程中引用访问控制数据,如角色和权限。
但是,由于许多Realm(如果不是大多数的话)都存储一个主题的两组数据,因此 Realm 的实现类更方便地使用 Account 接口的实现,这是一个结合了AuthenticationInfo 和 AuthorizationInfo 的方便接口。您是选择单独实现这两个接口,还是为给定领域实现一个帐户接口,完全取决于应用程序的需求或首选项。
用于保持认证和权限数据的上下文
ThreadContext:此类内部定义了一个 InheritableThreadLocal< Map< String, Object>> 实例对象,此实例对象会在用户(or 其它应用程序)首次调用本应用的方法时被put到被调用方法的执行本线程的 inheriableThreadLocalMap 中。
此实例对象的Map中会存储两个key-value,一个key是ThreadContext_SECURITY_MANAGER_KEY,一个是ThreadContext_SUBJECT_KEY。
SubjectContext:此类内部持有securityManager、session、subject、principals、authenticationInfo、authenticaitonToken、sessionCreationEnabled、authencitated 等数据。
SessionContext:DefaultSessionContext 有host 、sessionId属性。WebSessionContext增加了 request 、response属性
SessionManager: A SessionManager manages the creation, maintenance, and clean-up of all application Sessions. 相当于session对象的Service 层。
Session:有set / get / removeAttribute 方法;有 id, startTimeStamp, lastAccessTime, timeout, host, attributeKeys 属性
SubjectDao:其默认实现是DefaultSubjectDao,默认将Subject实例存储到Subject’s Session ,这样之后首次获取关联的 Session 时,会通过 SessionId 或 SessionKey 获取的SessionAttribute 重建Subject实例(通常是通过 SessionManager)。
用户可以自行控制 是否使用 Session 来保持自身状态,可以在javaConfig配置中设置SessionStorageEvaluator.
用于执行安全和权限校验的接口
-
Authenticator 接口:身份认证器,定义了 authenticate( authenticationToken) 方法,用于 身份校验
-
Authorizer 接口: 权限控制器,定义了 isPermitted 、hasRole 等接口方法,用于 权限验证
-
Realm 接口:身份读取器,定义了 getAuthentiction( authenticationToken) : AuthenticationInfo 方法,从数据库(或内存)中读取身份信息(根据提交来的用户账号信息- 参数authenticationToken中的数据)
Authenticator.authenticate 方法实际会调用Realm.getAuthentiction 接口方法,根据 token 从reallm 中查找有无相应 账户 和 凭据的 用户,如果返回值不会空,则说明用户的账户和凭据是正确的,认证通过。
Authorizer.isPermitted 方法实际会调用AuthorizingRealm.isPermitted( permission, principals )方法,会先根据 principal 去 Realm中获取用户的所有permissions,然后检查 给定的 permission 是否在用户的permissions集合中。
SecurityManager:继承了以下接口
- Authenticator (authenticate(authenticationToken)),
- Authorizer ( isPermitted hasRole )
- SessionManager ( start(SessionContext context) , Session getSession( sessionkey ))
定义了以下接口方法:
login( subject, authenticationToken)
logout( subject )
createSubject( subjectContext)
AuthenticatingSecurityManager:用于身份认证的抽象类,继承自RealmSecurityManager类。持有一个Authenticator 认证器对象,对 authenticate 方法的实现,都是直接调用 authenticator 对象的方法来实现。
AuthorizingSecurityManager:用于权限控制的抽象类,间接实现了SecurityManager接口。持有一个authorizer对象,对hasRole、isPermited 的方法的实现,都是直接调用 authorizer 对象的方法实现的。