目录
- 1、第一阶段:启动服务,构建类的功能
- 2、第二阶段:正式请求
1、第一阶段:启动服务,构建类的功能
查看 Shiro 配置类 ShiroConfiguration:
@Configuration
public class ShiroConfiguration {
// 创建 shiroFilter,负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//给filter设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map<String,String> map = new HashMap<>();
// authc 请求这个资源需要认证和授权
map.put("/login", "anon");
map.put("/register", "anon");
map.put("/user/register", "anon");
map.put("/user/login", "anon");
map.put("/index", "authc");
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
}
配置了 ShiroFilterFactoryBean
查看 ShiroFilterFactoryBean:实现了 FactoryBean 接口
public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {
private SecurityManager securityManager;
// 用于自定义的 filter
private Map<String, Filter> filters = new LinkedHashMap();
// 用于自定义的过滤器链
private Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
// 设置全局的 url
private String loginUrl;
private String successUrl;
private String unauthorizedUrl;
// 生成的实例
private AbstractShiroFilter instance;
// ...
public Object getObject() throws Exception {
if (this.instance == null) {
this.instance = this.createInstance();
}
return this.instance;
}
protected AbstractShiroFilter createInstance() throws Exception {
log.debug("Creating Shiro Filter instance.");
FilterChainManager manager = this.createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
}
// ...
}
Map<String, Filter> filters:key 是过滤器名称,value 是FilterMap<String, String> filterChainDefinitionMap:key 是 uri,value 是过滤器名称
Spring 容器会自动检测到 FactoryBean 接口,并调用其 getObject() 方法获取实际的 bean 对象,所以,最终会调用 createInstance() 方法。
createInstance()方法:创建FilterChainManager对象、PathMatchingFilterChainResolver(PathMatchingFilterChainResolver设置了FilterChainManager)对象,再创建了内部类SpringShiroFilter对象
this.createFilterChainManager():创建FilterChainManager。- 创建
DefaultFilterChainManager实例,并将默认过滤器、自定义过滤器存放到属性 Map<String, Filter> filters ; - 并给所有的过滤器设置
url:loginUrl、successUrl、unauthorizedUrl - 构造过滤器链,并存放到属性 Map<String, NamedFilterList> filterChains,其中,key 为
uri,value 为NamedFilterList (extends List<Filter>);并将 uri 存放在PathMatchingFilter类的 Map<String, Object> appliedPaths 属性
- 创建
createFilterChainManager() 方法:

①:new DefaultFilterChainManager():管理 过滤器 filters(包括默认过滤器 + 自定义过滤器)、过滤器链

在构造器中,将默认的过滤器添加到 filters 属性中
默认过滤器 DefaultFilter:枚举类
public enum DefaultFilter {
anon(AnonymousFilter.class),
authc(FormAuthenticationFilter.class),
authcBasic(BasicHttpAuthenticationFilter.class),
authcBearer(BearerHttpAuthenticationFilter.class),
logout(LogoutFilter.class),
noSessionCreation(NoSessionCreationFilter.class),
perms(PermissionsAuthorizationFilter.class),
port(PortFilter.class),
rest(HttpMethodPermissionFilter.class),
roles(RolesAuthorizationFilter.class),
ssl(SslFilter.class),
user(UserFilter.class);
}
②:applyGlobalPropertiesIfNecessary(filter):设置 loginUrl、successUrl、unauthorizedUrl

以 applyLoginUrlIfNecessary() 方法为例:


如果 ShiroFilterFactoryBean#loginUrl 有值且 AccessControlFilter#loginUrl 的值为默认值(/login.jsp),那么就会给 AccessControlFilter#loginUrl 设置值
③:处理自定义的过滤器 filter:将自定义过滤器添加到 DefaultFilterChainManager 中

④:getFilterChainDefinitionMap() & createChain():构造过滤器链
createChain() 方法:

注意下面这行代码:
String[] filterTokens = this.splitChainDefinition(chainDefinition);
将一个字符串可以转化为字符串数组,就可猜测是不是可以配置多个过滤器 map.put("/login", "anon, authc");
对此数组进行 for 循环:
String[] nameConfigPair = this.toNameConfigPair(token);
this.addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
又将一个字符串 token 转化为了一个 字符串数组,且通过 "[" (toNameConfigPair 内部实现)将数组分为了两部分
所以,最终可以配置成:
map.put("/login", "authc, roles[admin,user], perms[file:edit]");
addToChain() 方法:生成带有 name(过滤 uri)的过滤器链 NamedFilterList,并将过滤器添加其中(过滤 uri 和过滤器是一对多关系)

1、applyChainConfig() 方法:存放所有的过滤 uri

1-1、PathMatchingFilter#processPathConfig() 方法:
- 属性
PatternMatcher pathMatcher:用于请求 uri 和已配置的 uri 进行配置Map<String, Object> appliedPaths: 存放所有的过滤 uri

2、ensureChain(chainName) 方法:通过 uri 获取过滤器链,如果没有,则创建 SimpleNamedFilterList,并将此过滤器链放入 filterChains 属性中,返回;如果通过 uri 获取到过滤器链,则直接返回

2-1、SimpleNamedFilterList:其实就是一个有名字 name 的 List<Filter>。
- name:uri
List<Filter>:配置的过滤器
一个 uri 可以对应多个过滤器,所以,Filter 是一个 List 集合

new PathMatchingFilterChainResolver():创建PathMatchingFilterChainResolver,负责路径和过滤器链的解析、匹配,根据 url 找到过滤器链
2、第二阶段:正式请求
任何请求都会先经过 Shiro 先过滤,直到成功才会执行 web 本身的过滤器
一个请求过来时,先到达 AbstractShiroFilter#executeChain()方法,去根据 request 解析出来的 url 找到对应的过滤链,然后执行过滤器链。
1、executeChain() 方法如下:

1-1、getExecutionChain() 方法:这里的 resolver 就是 PathMatchingFilterChainResolver,根据 uri 获取过滤器链 ProxiedFilterChain

1-2、getChain() 方法:从属性 filterChains 循环匹配请求 uri,若匹配成功,则调用 filterChainManager.proxy();否则,返回 null

1-2-1、pathMatches() 方法:

1-2-1-1、AntPathMatcher#matches():使用 AntPathMatcher 进行匹配

doMatch():匹配 uri 和 requestUri,考虑到通配符 **。

2、chain.doFilter(request, response);:执行过滤器链


过滤器类结构图:

最终调用 AdviceFilter#doFilterInternal() 方法:由 preHandle() 方法决定过滤器链是否执行:

通过属性 appliedPaths 循环判断是否与当前请求的 uri 相匹配,如果通过,直接返回 true,否则,进入 onPreHandle() 方法判断:

onPreHandle() 方法供子类去重写:

如 AnonymousFilter:匿名访问。

任何对象访问都一直返回 true,表明任何用 AnonymousFilter 过滤的请求都不需要验证。因为它一直返回 true
AccessControlFilter:需要身份验证的过滤器

由 isAccessAllowed()、onAccessDenied() 方法决定
isAccessAllowed():决定了当前请求的subject是否允许访问onAccessDenied():在被拒绝访问时处理。AccessControlFilter 类有很多子类重载了该方法。以FormAuthenticationFilter类的onAccessDenied()方法为例

如果是登陆请求,则执行登陆操作;否则,保存请求链接跳转到登陆请求界面
executeLogin() 方法:创建 token,调用 Subject#login() 方法

总结流程:













![[笔记] 电机工作制以及软硬特性的本质推导](https://i-blog.csdnimg.cn/direct/3e84b0744fa1414583d0777a00941439.png)





