前阵子对shiro进行分布式环境下的改造时跟了一遍源码,当时只是使用了思维带图简要的记录了一下方法的调用过程。最近有空了决定用博客详细的记录分析一下这个流程,以帮助自己更好的理解。
###配置
首先看看shiro在web.xml文件中的配置
<!-- shiro过滤器 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
可以看到使用的<filter-class>标签是Spring的代理过滤器,那么它是如何代理shiro的过滤器的呢?看看DelegatingFilterProxy的源码
@Override
protected void initFilterBean() throws ServletException {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
// If no target bean name specified, use filter name.
//如果没有delegate则根据<filter-name>去Spring容器中寻找对应的bean
if (this.targetBeanName == null) {
this.targetBeanName = getFilterName();
}
// Fetch Spring root application context and initialize the delegate early,
// if possible. If the root application context will be started after this
// filter proxy, we'll have to resort to lazy initialization.
WebApplicationContext wac = findWebApplicationContext();
if (wac != null) {
this.delegate = initDelegate(wac);
}
}
}
}
于是Spring中应该配置了name为shiroFilter的bean,下面看看Spring中与shiro相关的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- shiroFilter对象 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/user/loginpage"/>
<property name="unauthorizedUrl" value="/403.html"/>
<property name="filterChainDefinitions">
<value>
/user/loginpage = anon
/user/login = anon
/* = authc
/user/perms1 = perms["user:delete"]
/user/perms2 = perms["user:select"]
/user/admin = roles["admin"]
#自定义的过滤器,只要多个权限中有一个满足即可
/user/users = rolesOr["admin","user"]
</value>
</property>
<property name="filters">
<map>
<entry key="rolesOr" value-ref="rolesOrFilter" />
</map>
</property>
</bean>
<!-- 创建securityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="realm"></property>
<property name="sessionManager" ref="sessionManager"></property>
</bean>
<!-- 创建realm -->
<bean id="realm" class="com.cfh.studyshiro.common.CustomeRealm">
</bean>
<!-- 自定义过滤器 -->
<bean id="rolesOrFilter" class="com.cfh.studyshiro.filter.RolesOrFilter" />
<!-- 注入自定义的sessionDao -->
<bean id="redisSessionDao" class="com.cfh.studyshiro.common.RedisSessionDao" />
<!-- 在sessionManager中引入自定义的sessionDao -->
<bean id="sessionManager" class="com.cfh.studyshiro.common.CustomSessionManager">
<property name="sessionDAO" ref="redisSessionDao" />
<!-- 关闭cookie -->
<!-- <property name="sessionIdCookieEnabled" value="false" /> -->
</bean>
</beans>
ShiroFilterFactoryBean的源码这里不进行讨论,先看看ShiroFilterFactoryBean.class中生成ShiroFilter的createInstance()方法
protected AbstractShiroFilter createInstance() throws Exception {
log.debug("Creating Shiro Filter instance.");
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