shiro原理分析
- 1、shiro如何介入你的spring程序
基本流程是
调用FilterRegistrationBean向spring注册过滤器-->使用DelegatingFilterProxy代理过滤器-->代理过滤器以bean的形式获取过滤器
shiro通过监听器来介入你的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授权过滤器代理类,该类继承了GenericFilterBean通用过滤器类,并且可以像管理spring bean一样,把过滤器作为一个bean来委托给spring管理其生存周期,其依赖关系如图所示
该类实现了Filter接口,在过滤器初始化时,调用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(); //调用子类的初始化方法
if (logger.isDebugEnabled()) {
logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
}
}
在该方法的最后会调用initFilterBean()方法,该方法是别其子类DelegatingFilterProxy重写了,所以会调用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);
}
虽然该类没有实现Filter接口,但是在getObject()返回的类中是实现了该接口的类,这是我当时一直迷惑的地方,当时一直在疑问,为什么ShiroFilterFactoryBean 类没有实现Filter接口也可以被当做过滤器注入,当时我没有注意到该类不是普通的spring Bean而是FactoryBean,spring获取的Bean不是该类本身而是该类的getObject()方法返回的对象实例,在该创建实例方法中,最后返回的是SpringShiroFilter类,该类是**ShiroFilterFactoryBean **的一个静态内部类,传入了securityManager,这也是我们能够配置Shiro的核心组件SecurityManager的原因。