Shiro (一) 上下文环境初始化
来源:互联网 发布:网络用户行为分析 编辑:程序博客网 时间:2024/05/21 12:39
1. 初始化过程的类图
2. 初始化过程
2.1 首先需要在web.xml中专门负责接入shiro的filter: <!-- shiro 安全过滤器 --><filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param></filter><filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>并且需要放在所有filter中靠前的位置,比如需要放在siteMesh的过滤器之前(filter的执行顺序是按照配置文件中声明的顺序,shiro过滤器之前的)。DelegatingFilterProxy 表示这是一个代理filter,它会将实际的工作,交给spring配置文件中 id="shiroFilter" 的bean来处理: 而 shiroFilter在spring中的配置如下: <!-- Shiro的Web过滤器 --><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="unauthorizedUrl" value="/unauthorized"/> <property name="filters"> <util:map> <entry key="authc" value-ref="passThruAuthenticationFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /reg/** = anon <!-- 注册相关 --> /login = authc /logout = logout /authenticated = authc /loginController = anon /js/** = anon /css/** = anon /img/** = anon /html/** = anon /font-awesome/** = anon <!-- /** = anon /user/modifyPassword = perms["user:update", "user:select"] --> /** = user </value> </property></bean>
DelegatingFilterProxy继承自GenericFilterBean, 其的init方法初始化DelegatingFilterProxy,这里 initFilterBean()方法在子类DelegatingFilterProxy中实现的(注意这种类似于模板的设计模式)
public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware, ServletContextAware, InitializingBean, DisposableBean { @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()); 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"); } }
这里判断delegate 是否为null,然后去初始化delegate 。
initFilterBean();
public class DelegatingFilterProxy extends GenericFilterBean { private String contextAttribute; private WebApplicationContext webApplicationContext; private String targetBeanName; private boolean targetFilterLifecycle = false; private volatile Filter delegate; private final Object delegateMonitor = new Object(); @Override protected void initFilterBean() throws ServletException { synchronized (this.delegateMonitor) { if (this.delegate == null) { // If no target bean name specified, use filter name. 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); } } } }
// Let subclasses do whatever initialization they like.
Filter 接口的 init 方法调用 initFilterBean(), 而该方法在子类中进行实现,它先获得 this.targetBeanName = getFilterName(); bean的名称,也就是id,然后对其进行初始化:this.delegate = initDelegate(wac); 其实就是从bean工厂中根据bean的名称找到bean.这里bean的名字是web.xml配置文件里DelegatingFilterProxy 这个filter的id,即shiroFilter(这是一个FactoryBean),所以这里wac.getBean(getTargetBeanName(), Filter.class)得到的实际是TargetBeanName代表的org.apache.shiro.spring.web.ShiroFilterFactoryBean,执行其init方法初始化delegate。
protected Filter initDelegate(WebApplicationContext wac) throws ServletException { Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } return delegate; }
这里wac.getBean会去初始化这个FactoryBean(shiroFilter),由于ShiroFilterFactoryBean是个FactroyBean,所以上面的delegate真正的对象是通过它的getObject()获取的。这里是FactoryBean接口获取实例的标准方法。
public Object getObject() throws Exception { if (instance == null) { instance = createInstance(); } return instance; }
这里是真正创建对象的方法,所以真正完成实际工作的过滤器是SpringShiroFilter,这个对象才是真正的delegate。
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); }
SpringShiroFilter是ShiroFilterFactoryBean的内部类,继承AbstractShiroFilter。SpringShiroFilter 的构造方法中设置好了securityManager和filterChainResolver。
private static final class SpringShiroFilter extends AbstractShiroFilter { protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) { super(); if (webSecurityManager == null) { throw new IllegalArgumentException("WebSecurityManager property cannot be null."); } setSecurityManager(webSecurityManager); if (resolver != null) { setFilterChainResolver(resolver); } }
所以delegate.init(getFilterConfig())实际是调用的SpringShiroFilter的init方法,SpringShiroFilter继承自AbstractFilter的init方法
public final void init(FilterConfig filterConfig) throws ServletException { setFilterConfig(filterConfig); try { onFilterConfigSet(); } catch (Exception e) { if (e instanceof ServletException) { throw (ServletException) e; } else { if (log.isErrorEnabled()) { log.error("Unable to start Filter: [" + e.getMessage() + "].", e); } throw new ServletException(e); } } }
onFilterConfigSet在AbstractFilter的实现类AbstractShiroFilter中实现,
protected final void onFilterConfigSet() throws Exception { //added in 1.2 for SHIRO-287: applyStaticSecurityManagerEnabledConfig(); init(); ensureSecurityManager(); //added in 1.2 for SHIRO-287: if (isStaticSecurityManagerEnabled()) { SecurityUtils.setSecurityManager(getSecurityManager()); } }
这里的init方法是调用AbstractShiroFilter的子类ShiroFilter的实现,
public void init() throws Exception { WebEnvironment env = WebUtils.getRequiredWebEnvironment(getServletContext()); setSecurityManager(env.getWebSecurityManager()); FilterChainResolver resolver = env.getFilterChainResolver(); if (resolver != null) { setFilterChainResolver(resolver); } }
对于 securityManager和filterChainResolver的初始化过程:
首先spring启动时,会把配置的 这个bean初始化,
ShiroFilterFactoryBean有一个构造方法如下,初始化了两个map:filters和filterChainDefinitionMap;初始化这个bean就会根据配置文件初始化securityManager,filters,filterChainDefinitionMap 。
根据配置文件中(比如applicationContext.xml)设置的securityManager,filters(customAuthenticationFilter)。还有setFilterChainDefinitions函数,传入它的String参数definitions便是“/reg/**= anon,/login = authc”,该函数读取这些配置,构造相应的section,并放入filterChainDefinitionMap中,注意这里完全按照上面配置文件的配置顺序添加filterChainDefinition到map里,在匹配过滤链时,会按照这个顺序匹配,只要匹配到就会终止继续匹配,所以在配置filterChainDefinitions的时候要注意顺序。
- Shiro (一) 上下文环境初始化
- SpringMVC学习笔记(一) DispatcherServlet初始化详解(应用上下文的初始化)
- SpringMVC之浅析上下文初始化(一)
- 上下文环境(Contexts)
- yii 随笔(一):初始化环境
- Android -- Activity启动过程中的上下文环境初始化分析
- shiro笔记(一)
- shiro学习(一)
- (一)初时shiro
- shiro实战(一)
- shiro学习(一)
- shiro学习(一)
- shiro 认证(一)
- (一)Shiro简介
- Shiro (一)
- shiro(一)
- 初识shiro(一)
- Shiro(一) Shiro架构介绍
- CodeForces-629A-Far Relative’s Birthday Cake
- ORACLE10G卸载过程
- CodeForces-629B-Far Relative’s Problem
- XMPP即时通讯机制
- js 上下左右轮播的实现
- Shiro (一) 上下文环境初始化
- halcon导出类---HDevWindowStack详解
- 关于NN以及BP的一些网络上整理的资料
- SOA服务设计原则
- Kotlin
- TCP传输控制协议
- Flask Web开发 Bootstrap 模板
- centos 7 安装python3.x
- CodeForces-629C-Famil Door and Brackets