> 文档中心 > [开发框架]-shiro-2-组件分析

[开发框架]-shiro-2-组件分析


shiro架构分析

shiro官方文档

全局工具类SecurityUtils

org.apache.shiro包下的一个类。SecurityUtils类中提供了设置主体,获取主体,设置安全管理器,获取安全管理器的方法

主体subject

subject类图
DelegatingSubject类中重写了login()方法:

public void login(AuthenticationToken token) throws AuthenticationException { this.clearRunAsIdentitiesInternal(); Subject subject = this.securityManager.login(this, token); ........}

该方法调用了SecurityManager中的login()方法

关于安全管理器SecurityManager

org.apache.shiro.mgt包下(mgt即management),根据文档的说法,SecurityManager继承了Authenticator, Authorizer, and SessionManager,将他们分别要做的行为合并到同一个地方来执行,对于大部分shiro的使用场景,这样做简化了配置,而且比分开使用Authenticator, Authorizer, and SessionManager 的实例要更简便,一个个体只需要跟一个单独的SecurityManager产生关联
除了继承的三个接口以外,SecurityManager还提供了一些支持subject行为的方法。对于单一一个用户,subject需要执行authentication, authorization, and session operations,而SecurityManager对这三个功能都能掌控,而三个父接口与subject并没有什么联系,如果将subject相关的某些操作交给他们来做,无法确保Separation of Concerns,关注点分离

Separation of Concerns,关注点分离,将一个程序分割成不同模块,一个模块只关心一个点,类似于职责分离

securitymanager相关类图
从抽象类的继承中我们可以看出每一次继承都完善了securitymanager的功能,CachingSecurityManager增添了缓存的管理CacheManagerRealmSecurityManager中增添了realmAuthenticatingSecurityManagerAuthorizingSecurityManager分别增添了AuthenticatorAuthorizer。所以安全管理器用来集成realm,认证器跟授权器

public interface SecurityManager extends Authenticator, Authorizer, SessionManager {    Subject login(Subject var1, AuthenticationToken var2) throws AuthenticationException;    void logout(Subject var1);    Subject createSubject(SubjectContext var1);}

SecurityManager中提供了login()方法以及createSubject()方法,在SecurityUtils中创建主体就是用这个方法
login()方法是在DefaultSecurityManager中被实现的,DefaultSecurityManager已经间接继承了AuthenticatingSecurityManager类,所以在login()方法中调用了authenticate()方法进一步调用认证器authenticator中的抽象方法doAuthenticate()进行认证

DefaultSecurityManager

常用方法:
[开发框架]-shiro-2-组件分析

Realm

[开发框架]-shiro-2-组件分析
根据文档的说法,AuthenticatingRealm是顶层的Realm接口的抽象实现类,而且它只完善了authentication的支持,authorization的部分留给了子类来完善;AuthorizingRealm就继承了AuthenticatingRealm,增加了authorization的支持,所以一般会选择继承AuthorizingRealm来自定义realm,重写其中的doGetAuthorizationInfo()方法和doGetAuthenticationInfo()方法

认证器authenticator

Authenticator中提供了authenticate()方法用于认证:

package org.apache.shiro.authc;public interface Authenticator {    AuthenticationInfo authenticate(AuthenticationToken var1) throws AuthenticationException;}

同级目录下的AbstractAuthenticator是几乎所有Authenticator实现类的超类,它设置了authentication时一些普遍的工作。他把具体的事实上的authentication过程交给子类来完成,然后自己支持当登陆或登出成功或失败时向监听器通知,从而触发相应的处理逻辑。在大部分情况下,子类唯一需要做的事就是实现doAuthenticate()方法来对接收的token完善具体的认证流程
authenticator类图

org.apache.shiro.authc.pam包下的ModularRealmAuthenticator类中就继承了AbstractAuthenticator,实现了doAuthenticate()

protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {    this.assertRealmsConfigured();    Collection<Realm> realms = this.getRealms();    return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);}

可以看出ModularRealmAuthenticator将账户查找交给Realm来完成。同级目录下还有AuthenticationStrategy接口,认证策略
认证策略

认证策略类图
FirstSuccessfulStrategy:只要一个 Realm 验证成功即可,只返回第 一个 Realm 身份验证成功的认证信息,其他的忽略
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,将返回所有Realm身份验证成功的认证信 息
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有 Realm身份验证成功的认证信息
ModularRealmAuthenticator默认是AtLeastOneSuccessfulStrategy策略

RealmSecurityManager类:

public void setRealms(Collection<Realm> realms) {    if (realms == null) { throw new IllegalArgumentException("Realms collection argument cannot be null.");    } else if (realms.isEmpty()) { throw new IllegalArgumentException("Realms collection argument cannot be empty.");    } else { this.realms = realms; this.afterRealmsSet();    }}

在设置完realm后会自己调用afterRealmsSet()方法,在AuthenticatingSecurityManager中会通过这个方法将realm同时设为认证器authenticator的realm:

protected void afterRealmsSet() {    super.afterRealmsSet();    if (this.authenticator instanceof ModularRealmAuthenticator) { ((ModularRealmAuthenticator)this.authenticator).setRealms(this.getRealms());    }}

也就是说,在DefaultSecurityManager类对象中调用setRealm()方法,认证器的realm也会保持一致

认证信息

SimpleAuthenticationInfo
[开发框架]-shiro-2-组件分析

过滤器

org.apache.shiro.web.filter包下,PathConfigProcessor接口为每个url请求处理配置条目
PathMatchingFilter抽象类是所有只会处理指定路径,让其他路径直接通过的拦截器的基类
AccessControlFilter抽象类继承了PathMatchingFilter,是所有会对资源访问进行控制的拦截器的超类。该类中有一个字段DEFAULT_LOGIN_URL,值为"/login.jsp",将"/login.jsp"默认设为用于登录的URL。getSubject() 方法可用于获取该请求对应的subject;isAccessAllowed() 方法,当请求被允许正常通过拦截器时返回true,否则返回false,这个请求应当被onAccessDenied处理;onPreHandle() 当isAccessAllowed方法通过时返回true,否则返回onAccessDenied方法的返回值
org.apache.shiro.web.filter.authc包下。这些过滤器有的是javax.servlet包下的Filter接口的实现类,用来对用户访问进行控制;有的则是可以直接执行认证操作的
抽象类AuthenticationFilter是所有要求当前用户进行认证的过滤器的基类,其中实现了isAccessAllowed()方法:当主体已被认证且身份信息不为空时返回true
抽象类AuthenticatingFilter在AuthenticationFilter基础上已有能力可以自己实现一个认证操作
较为常用的BasicHttpAuthenticationFilter。getPrincipalsAndCredentials() 方法用于从请求头中获取用户名和密码
shiro自带过滤器

过滤器工厂

org.apache.shiro.spring.web包下的ShiroFilterFactoryBean。filterChainDefinitionMap中放的是要拦截的路径以及相对应的过滤器;filters中放的是过滤器以及过滤器对应的名称,这个名称用于在filterChainDefinitionMap中设置过滤器时使用;loginUrl是应用中用于登陆的Url,所有AccessControlFilter的子类都有这个字段;setSecurityManager,设置安全管理器
将这个类在shiro的配置类中配置即可实现过滤器的配置

k歌软件