Q1:shiro过滤器是如何添加到servlet的过滤器链?和servlet原生拦截器是如何配合工作的?shiro是如何filter是如何拦截请求的?
Q3:shiro是如何实现账号密码验证的?
Q4:shiro是如何实现角色权限认证的?
A1:
ShiroFilterFactoryBean的getObject方法(实现spring的FactoryBean工厂方法),会创建一个SpringShiroFilter的Bean:
protected AbstractShiroFilter createInstance() throws Exception {
FilterChainManager manager = this.createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
// 设置了FilterChainManager和PathMatchingFilterChainResolver ,它将根据请求url,决定是否执行shrio代理链
chainResolver.setFilterChainManager(manager);
return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
}
SpringShiroFilter 是实现了Filter接口的,所以由spring自动加载到ServeltContext中,自然就加入了执行器链
几个主要类的父子关系:SpringShiroFilter -> AbstractFilter -> OncePerRequestFilter
父类:OncePerRequestFilter
Filter顶层接口doFilter的实现方法为这个方法,会加入到servlet的执行器链:
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) {
。。。。。。
this.doFilterInternal(request, response, filterChain);
。。。。。。
}
doFilterInternal是一个抽象方法,由子类AbstractFilter实现:
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) {
。。。
this.executeChain(request, response, chain);
。。。
}
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
// 获取执行器链,由执行器链执行doFilter
FilterChain chain = this.getExecutionChain(request, response, origChain);
chain.doFilter(request, response);
}
那么这个resolver拿到的chain到底是一个什么chain???
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
FilterChain chain = origChain;
FilterChainResolver resolver = this.getFilterChainResolver();
。。。
FilterChain resolved = resolver.getChain(request, response, origChain);
。。。
return chain;
}
resolver实际是一个PathMatchingFilterChainResolver对象
PathMatchingFilterChainResolver类
// 主要检查当前请求的url是否匹配shiro filter的拦截路径,如果是,则返回ProxiedFilterChain
public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
FilterChainManager filterChainManager = this.getFilterChainManager();
。。。。。。
return filterChainManager.proxy(originalChain, pathPattern);
}
DefaultFilterChainManager类
// 对象属性,已经实例化好了,filter不会反复创建,浪费资源;
// 打上断点发现:filterChains的key是url,value是filterList;如下图所示:
实际上一个url是可以配置多个filter的
Map
// 当登陆login的时候,断点发现:chainName = /login
public FilterChain proxy(FilterChain original, String chainName) {
// getChain从filterChains属性中获取的NamedFilterList
NamedFilterList configured = this.getChain(chainName);
if (configured == null) {
String msg = "There is no configured chain under the name/key [" + chainName + "].";
throw new IllegalArgumentException(msg);
} else {
return configured.proxy(original);
}
}
SimpleNamedFilterList类(NamedFilterList实现类)
public FilterChain proxy(FilterChain orig) {
// this指向就是shiro的Filters,实际上在DefaultFilterChainManager属性中已经实例化好了,orig是外部传入的原生执行器链,
// 所以需要new只是ProxiedFilterChain代理对象
return new ProxiedFilterChain(orig, this);
}
ProxiedFilterChain类(这就是常说shrio代理链)
public class ProxiedFilterChain implements FilterChain {
// 代理的原生的severlet处理器链
private FilterChain orig;
// shiro的filter链
private List
private int index = 0;
public ProxiedFilterChain(FilterChain orig, List
this.orig = orig;
this.filters = filters;
this.index = 0;
}
// 实现了FilterChain接口,适配标准的servlet处理器链
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (this.filters != null && this.filters.size() != this.index) {
((Filter)this.filters.get(this.index++)).doFilter(request, response, this);
} else {
// shiro的filter全部执行完成后,执行完成原生的处理器链
this.orig.doFilter(request, response);
}
}
}