shiro登入流程
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; }
待完成—-