ShiroFilter
Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter类似于如Strut2/SpringMVC这种web框架的前端
其是安全控制的入口点,其负责读取配置(如ini配置文件),然后判断URL是否需要登录/权限等工作。
web.xml配置名字为shiroFilter的过滤器,这个bean去 shiro.in 或者shiro.xml配置文件中找
首先是在web.xml中配置DelegatingFilterProxy
<!-- Shiro Security filter -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
配置好DelegatingFilterProxy后,下面只要再把ShiroFilter配置到Spring容器(此处为Spring的配置文件)即可:
(使用ShiroFilterFactoryBean创建shiroFilter)
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/" />
<property name="filterChainDefinitions">
<value>
/favicon.ico = anon
/assets/** = anon
/jd/** = anon
/uf/** = anon
/upload/** = anon
/upload-file = anon
/api/code = anon
/services/** = anon
/api/login = anon
/pushCall = anon
/oc/** = anon
/fl/** = anon
/login = authc
/logout = logout
/api/v2/oc/user/login=anon
/api/v2/oc/user/register=anon
/api/v2/oc/user/checkPhoneCode=anon
/api/v2/oc/user/reset/code=anon
/api/v2/oc/user/reset/password=anon
/api/v1/eam/**=mobile
/api/v2/**=mobile
/api/** = anon
/** = user
</value>
</property>
<!-- 做拦截过滤 -->
<property name="filters">
<map>
<entry key="mobile">
<bean class="com.xx.xx.shiro.filter.MobileAuthenticatingFilter"></bean>
</entry>
</map>
</property>
</bean>
使用了ShiroFilterFactoryBean来创建shiroFilter,这里用到了Spring中一种特殊的Bean——FactoryBean。当需要得到名为”shiroFilter“的bean时,会调用其getObject()来获取实例。下面我们通过分析ShiroFilterFactoryBean创建实例的过程来探究Shiro是如何实现安全拦截的:
ShiroFilterFactoryBean创建shiroFilter
public Object getObject() throws Exception {
if (instance == null) {
instance = createInstance();
}
return instance;
}
其中调用了createInstance()来创建实例:
protected AbstractShiroFilter createInstance() throws Exception {
// 这里是通过FactoryBean注入的SecurityManager(必须)
SecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
String msg = "SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if (!(securityManager instanceof WebSecurityManager)) {
String msg = "The security manager does not implement the WebSecurityManager interface."; throw new BeanInitializationException(msg);
}
FilterChainManager manager = createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
可以看到创建SpringShiroFilter时用到了两个组件:SecurityManager和ChainResolver。
先有一个大体的了解,那么对于源码分析会有不少帮助。下面会对以上两个重要的组件进行分析,包括PathMatchingFilterChainResolver和FilterChainManager。首先贴一段ShiroFilter的在配置文件中的定义:
========> ="filterChainDefinitions">
<value> /resources/** = anon
/download/** = anon
/special/unauthorized = anon
/register = anon
/logout = logout
/admin/** = roles[admin]
/** = user >
PathMatchingFilterChainResolver和FilterChainManager的创建过程:
protected FilterChainManager createFilterChainManager() {
//默认使用的FilterChainManager是DefaultFilterChainManager
DefaultFilterChainManager manager = new DefaultFilterChainManager();
// 将ShiroFilterFactoryBean配置的一些公共属性(上面配置的loginUrl,successUrl,unauthorizeUrl)应用到默认注册的filter上去
for (Filter filter : defaultFilters.values()) { applyGlobalPropertiesIfNecessary(filter);
}
Filter filters = getFilters();
if (!CollectionUtils.isEmpty(filters)) {
for (, Filter> entry : filters.entrySet()) {
Filter filter = entry.getValue(); applyGlobalPropertiesIfNecessary(filter);
if (filter instanceof Nameable) {
}
//将Filter添加到manager中去,可以看到对于Filter的管理是依赖于FilterChainManager的 manager.addFilter(name, filter, false);
}
}
String> chains = getFilterChainDefinitionMap();
for (String> entry : chains.entrySet()) {
String chainDefinition = entry.getValue();
manager.createChain(url, chainDefinition); } }
return manager; }
待完成—-