首页 文章 精选 留言 我的

精选列表

搜索[融合分析],共10000篇文章
优秀的个人博客,低调大师

Shiro源码分析---FilterChain创建过程

在Shiro中,无论是认证还是权限控制都是通过过滤器来实现的,在应用中可能会配置很多个过滤器,但对于不同的访问请求所需要经过的过滤器肯定是不一样的,那么当发起一个请求时,到底会应用上哪些过滤器,对于我们使用Shiro就显示得格外重要;下面就来讲讲一个请求到底会经过哪些过滤器。 在Shiro中,确证一个请求会经过哪些过滤器是通过org.apache.shiro.web.filter.mgt.FilterChainResolver接口来定义的,下面是接口定义: public interface FilterChainResolver { FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain); } 接口中只有一个方法getChain,就是用于确定请求到底要经过哪些过滤器,然后将这些过滤器封装成一个FilterChain对象,FilterCahin我们很熟悉,在使用Servlet的时候经常见面。FilterChainResolver只是一个接口,Shiro提供了一个默认的实现类org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver,该实现类会根据请求路径进行匹配过滤器。在看PathMatchingFilterChainResolver源码之前先说一下FilterChainManager中的FilterChain是怎么来的,以ini配置为例: [urls] /static/**=anon /formfilterlogin=authc /role=authc,roles[admin] 其中/static/**、/formfilterlogin,/role 就是受FilterChainManager管理的FilterChain的名称。下面看看FilterChainManager是如何管理FilterChain的。Shiro提供了FilterChainManager一个的默认实现:org.apache.shiro.web.filter.mgt.DefaultFilterChainManager,其createChain方法会在系统启动的时候被org.apache.shiro.web.config.IniFilterChainResolverFactory调用,用于创建各个FilterChain。下面以/role=authc,roles[admin]配置为例,chainName就是/role,chainDefinition就是authc,roles[admin] public void createChain(String chainName, String chainDefinition) { if (!StringUtils.hasText(chainName)) { throw new NullPointerException("chainName cannot be null or empty."); } if (!StringUtils.hasText(chainDefinition)) { throw new NullPointerException("chainDefinition cannot be null or empty."); } if (log.isDebugEnabled()) { log.debug("Creating chain [" + chainName + "] from String definition [" + chainDefinition + "]"); } // filterTokens数组有两个元素,第一个为authc,第二个为roles[admin],因为配置时可以配置多个Filter, // 多个Filter间以逗号分隔 String[] filterTokens = splitChainDefinition(chainDefinition); for (String token : filterTokens) { // 对roles[admin]进行分隔,数组中第一个元素为roles,第二个为admin String[] nameConfigPair = toNameConfigPair(token); // 添加FilterChain addToChain(chainName, nameConfigPair[0], nameConfigPair[1]); } } public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) { if (!StringUtils.hasText(chainName)) { throw new IllegalArgumentException("chainName cannot be null or empty."); } // 根据filterName(role)查找出Filter Filter filter = getFilter(filterName); if (filter == null) { throw new IllegalArgumentException("There is no filter with name '" + filterName + "' to apply to chain [" + chainName + "] in the pool of available Filters. Ensure a " + "filter with that name/path has first been registered with the addFilter method(s)."); } // 应用FilterChain配置,以roles[amdin]为例,调用该方法后roles过滤器就知道其进行拦截器需要admin角色 applyChainConfig(chainName, filter, chainSpecificFilterConfig); // 如果chainName以前没处理过则创建一个新的NamedFilterList对象,如果处理过则返回以前的NamedFilterList对象 // 所以在FilterChainManager中,存储Filter的是NamedFilterList对象 NamedFilterList chain = ensureChain(chainName); // 将过滤器添加至链中 chain.add(filter); } 在了解了FilterChainManager是如何创建与存储FilterChain以后,再来看看FilterChainResolver是如何确定一个请求需要经过哪些过滤器的。 public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) { FilterChainManager filterChainManager = getFilterChainManager(); // 判断FilterChainManager中是否有FilterChain,如果没有则返回null if (!filterChainManager.hasChains()) { return null; } // 获取请求URI String requestURI = getPathWithinApplication(request); // FilterChain的名称就是路径匹配符,如果请求URI匹配上了某个FilterChain // 则调用FilterChainManager.proxy方法返回一个FilterChain对象,注意是返回第一个匹配FilterChain // 也就是说如果在ini配置文件中配置了多个同名的FilterChain,则只有第一个FilterChain有效 for (String pathPattern : filterChainManager.getChainNames()) { if (pathMatches(pathPattern, requestURI)) { if (log.isTraceEnabled()) { log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "]. " + "Utilizing corresponding filter chain..."); } return filterChainManager.proxy(originalChain, pathPattern); } } return null; } 下面是DefualtFilterChainManager.proxy方法源码: public FilterChain proxy(FilterChain original, String chainName) { // 路径模式匹配(如/static/**)就是FilterChain名称 // 根据FilterChain名称查找NamedFilterList对象(存储了配置的Filter) NamedFilterList configured = getChain(chainName); if (configured == null) { String msg = "There is no configured chain under the name/key [" + chainName + "]."; throw new IllegalArgumentException(msg); } // 调用NamedFilterList.proxy方法 return configured.proxy(original); } NamedFilterList的实现类为org.apache.shiro.web.filter.mgt.SimpleNamedFilterList public FilterChain proxy(FilterChain orig) { // 返回ProxiedFilterChain对象,该对象就是当一个请求到来后需要被执行的FilterChain对象 // 该对象只是一个代理对象,代理了两个FilterChain,一个是NamedFilterList,另一个是原始的FilterChain对象 // 原始的FilterChain对象包含了在web.xml中配置并应用上的Filter return new ProxiedFilterChain(orig, this); } public class ProxiedFilterChain implements FilterChain { private static final Logger log = LoggerFactory.getLogger(ProxiedFilterChain.class); private FilterChain orig; private List<Filter> filters; private int index = 0; public ProxiedFilterChain(FilterChain orig, List<Filter> filters) { if (orig == null) { throw new NullPointerException("original FilterChain cannot be null."); } this.orig = orig; this.filters = filters; this.index = 0; } public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // 可以看出,先执行原始Filter,再执行NamedFilterList中的Filter if (this.filters == null || this.filters.size() == this.index) { //we've reached the end of the wrapped chain, so invoke the original one: if (log.isTraceEnabled()) { log.trace("Invoking original filter chain."); } this.orig.doFilter(request, response); } else { if (log.isTraceEnabled()) { log.trace("Invoking wrapped filter at index [" + this.index + "]"); } this.filters.get(this.index++).doFilter(request, response, this); } } } 至此,Shiro创建FilterChain过程讲解完毕,如有错误之处,尽请指正。 -------------------------------- END ------------------------------- 及时获取更多精彩文章,请关注公众号《Java精讲》。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册