当前位置: 首页 > news >正文

Shiro随笔(2:探讨FilterChainManager)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

由于本人文笔不好,写不出文风华丽的博客文章而懊恼不已,为此准备狂读三千道藏,嘻嘻嘿嘿!好吧,闲话不多聊,直接进入今天的主题吧。

直接上代码:


package org.apache.shiro.web.filter.mgt;

import org.apache.shiro.config.ConfigurationException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import java.util.Map;
import java.util.Set;

/**
 *A FilterChainManager manages the creation and modification of Filter chains from an available pool of Filter instances.
 *这个FilterChainManager管理来自过滤器实例池的过滤器链的修改和创建。
 */
public interface FilterChainManager {


    Map<String, Filter> getFilters();


    NamedFilterList getChain(String chainName);


    boolean hasChains();


    Set<String> getChainNames();


    void addFilter(String name, Filter filter);


    void addFilter(String name, Filter filter, boolean init);


    void createChain(String chainName, String chainDefinition);


    void addToChain(String chainName, String filterName);

    void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) throws ConfigurationException;
}

看到上面的代码,对于有过web开发经验的同学来说,很快就心领神会的明白各个方法应该具备怎么样的功能。但是小白者居多啊,我还是挑几个方法讲一下吧,因为的确有几个方法得注意一下,后文会用到。

首先:getFilters()与getChain(String chainName)方法有啥区别?一个是得到过滤器的集合,另一个是根据chainName得到相应的过滤器链。

getFilters():我们知道,每个过滤器都要有自己的一个名字name,以后根据名字找到相应的过滤器。在shiro框架中,FilterChainManager 创建实例的时候会预先添加一些默认的过滤器。如下:

(anon,AnonymousFilter)
(authc,FormAuthenticationFilter)
(authcBasic,BasicHttpAuthenticationFilter)
(logout,LogoutFilter)
(noSessionCreation,NoSessionCreationFilter)
(perms,PermissionsAuthorizationFilter)
(port,PortFilter)
(rest,HttpMethodPermissionFilter)
(roles,RolesAuthorizationFilter)
(ssl,SslFilter)
(user,UserFilter)

Map里面预先装下了这么些默认的过滤器,前面的是过滤器的名字,如:anon是过滤器AnonymousFilter的名字,authc是FormAuthenticationFilter的名字,等。随着项目工程继续往后执行的过程中,会往这个Map里面添加自定义的过滤器。请看spring-config-shiro.xml的部分代码,如下:

    <!-- 基于Form表单的身份验证过滤器 -->
    <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"/>

    <bean id="sysUserFilter" class="com.github.zhangkaitao.shiro.chapter16.web.shiro.filter.SysUserFilter"/>

    <!-- Shiro的Web过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login"/>
        <property name="filters">
            <util:map>
                <entry key="authc" value-ref="formAuthenticationFilter"/>
                <entry key="sysUser" value-ref="sysUserFilter"/>
            </util:map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /login = authc
                /logout = logout
                /authenticated = authc
                /** = user,sysUser
            </value>
        </property>
    </bean>

如上代码可看出,自定义了两个filter,一个是名字为authc的FormAuthenticationFilter过滤器,另一个是名字为sysUser的SysUserFilter的过滤器。

getChain(String chainName):根据chainName得到NamedFilterList,这个NamedFilterList其实就是一个List集合,里面专门用来存一个或者多个filter的。那么chainName是啥呢?用来干啥的呢?不要怕,由我慢慢道来。其实我在上面贴出的代码里,已经用到了chainName的概念。如下图:

从上图更加直观的看出这些请求路径就是chainName。对应的过滤器(一个或者多个)会放进对应的NamedFilterList集合中。

接下来再来讲讲createChain()方法:官方给出的解释如下

Creates a filter chain for the given chainName with the specified chainDefinition String. 

Conventional Use
Because the FilterChainManager interface does not impose any restrictions on filter chain names, (it expects only Strings), a convenient convention is to make the chain name an actual URL path expression (such as an Ant path expression). For example: 
createChain(path_expression, path_specific_filter_chain_definition); This convention can be used by a FilterChainResolver to inspect request URL paths against the chain name (path) and, if a match is found, return the corresponding chain for runtime filtering. 

Chain Definition Format
The chainDefinition method argument is expected to conform to the following format:  filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]
where 
1.filterN is the name of a filter previously registered with the manager, and
2.[optional_configN] is an optional bracketed string that has meaning for that particular filter for this particular chain
If the filter does not need specific config for that chain name/URL path, you may discard the brackets - that is, filterN[] just becomes filterN. 
And because this method does create a chain, remember that order matters! The comma-delimited filter tokens in the chainDefinition specify the chain's execution order. 

Examples
/account/** = authcBasic
This example says "Create a filter named '/account/**' consisting of only the 'authcBasic' filter". Also because the authcBasic filter does not need any path-specific config, it doesn't have any config brackets []. 

/remoting/** = authcBasic, roles[b2bClient], perms["remote:invoke:wan,lan"]
This example by contrast uses the 'roles' and 'perms' filters which do use bracket notation. This definition says: 
Construct a filter chain named '/remoting/**' which 
1.ensures the user is first authenticated (authcBasic) then
2.ensures that user has the b2bClient role, and then finally
3.ensures that they have the remote:invoke:lan,wan permission.

Note: because elements within brackets [ ] can be comma-delimited themselves, you must quote the internal bracket definition if commas are needed (the above example has 'lan,wan'). If we didn't do that, the parser would interpret the chain definition as four tokens: 
1.authcBasic
2.roles[b2bclient]
3.perms[remote:invoke:lan
4.wan]
which is obviously incorrect. So remember to use quotes if your internal bracket definitions need to use commas.

好吧,我来翻译一下。鄙人英语水品有限,难免出错,恳求各位谅解并留下你宝贵的纠错。

给给定的带有chainDefinition字符串的chainName创建一个过滤器链。

FilterChainManager接口没有强加一些限制在过滤器链的名字上,期望的就仅仅是字符串。一个方便的约定就是让chain name符合url路径的表达式,比如Ant风格的路径表达式。
这种约定能够让FilterChainResolver 去检查请求的url路径与chain name作比较,如果匹配上了,则返回对应的过滤器链。

chainDefinition方法的参数要符合接下来的格式:
filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]。
这个"filterN"是先前已经在FilterChainManager注册过的过滤器的名字。
这个[optional_configN]是可选的带有括号的字符串给那些特定的字符串在这个过滤器链上。
如果这个过滤器没有指定的配置在这个chain name的url路径上,那么filterN[]就等同于filterN。
因为这个方法创建过滤器链,记住这个顺序的重要性。
在chain definition上的逗号分隔的过滤器令牌指定了过滤器链的执行顺序。
我自己都感觉到翻译的一塌糊涂,直接看例子吧)

比如:/login = authc,role[devil]。
"/login"就是chain name前面已经说过了,"="号后面的就是chainDefinition,也就是"authc,role[devil]",逗号把各个过滤器隔离开来了。
用String的split方法得到String数组。String[0]=authc,String[1]=role[devil],所以根据官方文档给出的过滤器链执行顺序就是先执行名字为authc的过滤器,第二个执行名字为role的过滤器。
大家注意到了role[devil],括号里面带有参数devil,在shiro框架中的称呼是chainSpecificFilterConfig。
现在举个例子,假如这个过滤器是处理角色功能的,那么就只有devil角色的用户才能有权利访问该路径下的资源。

note:在这里扩从一个知识点,在自定义的过滤器中,如果你想使用这种带括号的功能,如role[devil],则你自定义的过滤器必须实现PathConfigProcessor接口

FilterChainManager是一个抽象接口,在web开发中,shiro框架中已经提供了实现方案。

DefaultFilterChainManager实现了这个接口。

 

这个FilterChainManager接口介绍就先到这里。下面来探讨一下它的初始化流程。

在前面的一篇博客文章中:shiro随笔(1:web.xml中的过滤器配置里,spring是如何关联shiro的)已经提到过ShiroFilterFactoryBean,没错就是由它来初始化FilterChainManager的,毕竟它是shiro的入口,那么肯定是由它来负责的。找到该类的createFilterChainManager()方法,如下图:

在shiro随笔(1:web.xml中的过滤器配置里,spring是如何关联shiro的)博客文章中讲过,

org.springframework.web.filter.DelegatingFilterProxy会经过层层调用,

直到调用到org.apache.shiro.spring.web.ShiroFilterFactoryBean的getObject()方法,来看一下这个方法

    public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }

接下来回去调用createInstance()方法:

好了,今天就写到这里了,哇塞,已经晚上11点了,该洗洗睡觉了。各位至今还奋斗在深夜的同行们,祝大家保重龙体!如果这篇文章能够帮助到大家,欢迎转载并注明出处。

转载于:https://my.oschina.net/u/2381372/blog/1204706

相关文章:

  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • SonarQube 安装
  • Spark RDDs vs DataFrames vs SparkSQL
  • CS61B LAB1
  • mysql HA 负载均衡
  • linux下如何判断oracle数据库tns是否设置正常
  • bzoj 2038 [2009国家集训队]小Z的袜子(hose) 莫队算法
  • VS2008让Release配置也能调试起来~
  • 图解Activity启动流程,进阶高级
  • 面向对象原则之一 迪米特法则
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 关于TRIM的优化技巧
  • 切换tab页
  • 哈希算法 加密算法
  • vuejs经验交流之-图片上传
  • 【技术性】Search知识
  • 2017届校招提前批面试回顾
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • Android开源项目规范总结
  • Babel配置的不完全指南
  • create-react-app项目添加less配置
  • ES6 学习笔记(一)let,const和解构赋值
  • extract-text-webpack-plugin用法
  • JAVA之继承和多态
  • VUE es6技巧写法(持续更新中~~~)
  • webpack入门学习手记(二)
  • 闭包,sync使用细节
  • 好的网址,关于.net 4.0 ,vs 2010
  • 计算机在识别图像时“看到”了什么?
  • 记一次用 NodeJs 实现模拟登录的思路
  • 技术:超级实用的电脑小技巧
  • 那些被忽略的 JavaScript 数组方法细节
  • 普通函数和构造函数的区别
  • 前端
  • 前端知识点整理(待续)
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 2017年360最后一道编程题
  • 通过调用文摘列表API获取文摘
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • ###C语言程序设计-----C语言学习(3)#
  • #define与typedef区别
  • #if 1...#endif
  • #laravel 通过手动安装依赖PHPExcel#
  • (42)STM32——LCD显示屏实验笔记
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (ZT)一个美国文科博士的YardLife
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (九十四)函数和二维数组
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (三分钟)速览传统边缘检测算子
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • ***详解账号泄露:全球约1亿用户已泄露