- 1、shiro如何介入你的spring程序
基本流程是
調(diào)用FilterRegistrationBean向spring注冊過濾器-->使用DelegatingFilterProxy代理過濾器-->代理過濾器以bean的形式獲取過濾器
shiro通過監(jiān)聽器來介入你的spring程序,在配置的時候
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
filterRegistration.setEnabled(true);
filterRegistration.addUrlPatterns("/*");
filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
return filterRegistration;
}
在set過濾器的時候使用了DelegatingFilterProxy授權(quán)過濾器代理類,該類繼承了GenericFilterBean通用過濾器類,并且可以像管理spring bean一樣,把過濾器作為一個bean來委托給spring管理其生存周期,其依賴關(guān)系如圖所示

該類實現(xiàn)了Filter接口,在過濾器初始化時,調(diào)用GenericFilterBean的init()方法,其源代碼如下所示
@Override
public final void init(FilterConfig filterConfig) throws ServletException {
Assert.notNull(filterConfig, "FilterConfig must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");
}
this.filterConfig = filterConfig;
// Set bean properties from init parameters.
try {
PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
String msg = "Failed to set bean properties on filter '" +
filterConfig.getFilterName() + "': " + ex.getMessage();
logger.error(msg, ex);
throw new NestedServletException(msg, ex);
}
// Let subclasses do whatever initialization they like.
initFilterBean(); //調(diào)用子類的初始化方法
if (logger.isDebugEnabled()) {
logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
}
}
在該方法的最后會調(diào)用initFilterBean()方法,該方法是別其子類DelegatingFilterProxy重寫了,所以會調(diào)用DelegatingFilterProxy的initFilterBean()方法,其運行棧如下所示
initFilterBean()-->initDelegate()
initDelegate()方法的源代碼為
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
在Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);中從程序的上下文中獲取bean,在這個地方獲取的bean是一個FactoryBean,獲取的不是他本身,而是其getObject()方法返回的對象,在上文中
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager());
bean.setLoginUrl("/api/user/login");
bean.setUnauthorizedUrl("/api/user/unauthor");
Map<String, Filter>filters = Maps.newHashMap();
filters.put("perms", urlPermissionsFilter());
filters.put("anon", new AnonymousFilter());
bean.setFilters(filters);
Map<String, String> chains = Maps.newHashMap();
chains.put("/api/user/login", "anon");
chains.put("/api/user/unauthor", "anon");
chains.put("/api/user/forgetpw", "anon");
chains.put("/api/user/register", "anon");
chains.put("/api/user/requestSMSCode", "anon");
chains.put("/base/**", "anon");
chains.put("/css/**", "anon");
chains.put("/layer/**", "anon");
chains.put("/**", "authc");
bean.setFilterChainDefinitionMap(chains);
return bean;
}
后面說了DelegatingFilterProxy類把名字為shiroFilter的Bean作為過濾器,注入的是**ShiroFilterFactoryBean **類,該類的getObject()方法為
public Object getObject() throws Exception {
if (instance == null) {
instance = createInstance();
}
return instance;
}
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 = createFilterChainManager();
//Expose the constructed FilterChainManager by first wrapping it in a
// FilterChainResolver implementation. The AbstractShiroFilter implementations
// do not know about FilterChainManagers - only resolvers:
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
//Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
//FilterChainResolver. It doesn't matter that the instance is an anonymous inner class
//here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
//injection of the SecurityManager and FilterChainResolver:
return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
雖然該類沒有實現(xiàn)Filter接口,但是在getObject()返回的類中是實現(xiàn)了該接口的類,這是我當(dāng)時一直迷惑的地方,當(dāng)時一直在疑問,為什么ShiroFilterFactoryBean 類沒有實現(xiàn)Filter接口也可以被當(dāng)做過濾器注入,當(dāng)時我沒有注意到該類不是普通的spring Bean而是FactoryBean,spring獲取的Bean不是該類本身而是該類的getObject()方法返回的對象實例,在該創(chuàng)建實例方法中,最后返回的是SpringShiroFilter類,該類是**ShiroFilterFactoryBean **的一個靜態(tài)內(nèi)部類,傳入了securityManager,這也是我們能夠配置Shiro的核心組件SecurityManager的原因。