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的时候要注意顺序。

2 0