Spring Security(Acegi)实现原理与应用一

1.引言:Spring  Security 是前身Acegi经过演变形成。主要是为咱们提供安全服务,主要包含验证,授权俩方面。

2.Spring  Security  实现原理和基本的过程,为了理解起来方便:先写我们较熟悉的场景——用户登陆-> 用户授权。

1)首先配置一个过滤器,很容易理解,我们web容器在开始操作前都会经过filter(实际上spring以DelegatingFilterProxy为入口,这个类里面存储了FilterChainProxy实例,至于说这些是什么意思我们向下看)

    <!-- Spring-Security -->
	<filter>
        <filter-name>mySpringSecurityFilterChain</filter-name>
		<filter-class>cn.com.nuskin.agelocme.config.DelegatingFilter</filter-class>
    </filter>

    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

public class DelegatingFilter extends DelegatingFilterProxy{
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws ServletException, IOException {
		
			
		HttpServletRequest httpRequest=(HttpServletRequest)request;

		String url = httpRequest.getRequestURI();
		if (url.indexOf("admin") != -1){
			
			super.doFilter(request, response, filterChain);
			return;
		}else{
			
			super.doFilter(request, response, filterChain);
		}
	}
	

我们可以看到 这样我们是做了准备工作.关注一下DelegatingFilterProxy这个类,我们可以在配置文件里直接使用该类,不用重新继承,这样做就是为了拓展.

DelegatingFilterProxy类继承于抽象类GenericFilterBean,间接地implement 了javax.servlet.Filter接口,Servlet容器在启动时,首先会调用Filter的i nit方法。GenericFilterBean实现了filter那么我们看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.
		<span style="color:#cc0000;">initFilterBean();</span>

		if (logger.isDebugEnabled()) {
			logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
		}
	}

看着红色部分,init方法设置了一些参数信息后调用initFilterBean来初始化filterBean该方法其实留给了子类来实现。这里其实就是我们的DelegatingFilterProxy initFilterBean方法。

	@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);
				}
			}
		}
	}

意思很好理解如果我们配置了targetBeanName那么我们就会去加载这个配置的filter,否则就是我们的targetBeanName就是springSecurityFilterChain(该名称spring里已经默认好spring org.springframework.security.FilterChainProxy实例的名称)。此处我们并没有设置这个参数的值那么就会取到默认的值。

然后最终通过initDelegate方法获取了我们的filter实例同时设置到了DelegatingFilterProxy类的delegate属性里。实例org.springframework.security.FilterChainProxy(该类也是继承了GenericFilterBean)。最后通过DelegatingFilterProxy invokeDelegate(delegateToUse, request, response, filterChain)方法响应处理请求。

总结:这里主要有俩个filter一个代理类DelegatingFilterProxy 一个实际起作用spring org.springframework.security.FilterChainProxy该过滤器。这样

使得FilterChainProxy 被代理了在DelegatingFilterProxy 下。这样做的好处是FilterChainProxy 独立出来可以动态配置,可以是默认的spring提供,也可以根据

根据targetBeanName来自定义过滤器,一般情况下我们就默认。下面就是来说们为什么 FilterChainProxy 如何配置,怎么就通过initDelegate方法获取到了实例了?

2)FilterChainProxy配置和原理

首先看一下initDelegate方法:

	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

关键点就在于getTargetBeanName方法。要想搞明白我们就得来说一下上文说到的security.xml,看个简单的

<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security.xsd">

	<http auto-config='true'>
		<intercept-url pattern="/**" access="ROLE_USER" />
		<http-basic />
	</http>


</beans:beans>

auto-config="true"属性,spring security就会自动配置好了过滤器链。其中原理可以参考:http://dead-knight.iteye.com/blog/1511389 博客。

那么我们说到的过滤连是什么意思呢,那么如何自定义?

   <bean id="securityFilterChainProxy"  
        class="org.springframework.security.web.FilterChainProxy">  
        <constructor-arg>  
            <list>  
                <security:filter-chain pattern="/services/**"  
                    filters="none" />  
                <security:filter-chain pattern="/test*" filters="none" />  
                <security:filter-chain pattern="/**"  
                    filters="person1Filter,person2Filter," />  
            </list>  
        </constructor-arg>  
    </bean> 

spring在加载配置文件 加载securityFilterChainProxy就会初始化该过滤链注意bean id 必须是securityFilterChainProxy因为我的web.xml  DelegatingFilter代理过滤器没有配置自定的filter默认的spring securityFilterChainProxy的过滤器,这里我们只是给他设置了一些自定义过滤连参数。这么多都是我们的前置配置。当然自己定义了实际的过滤器

例如:

<init-param> 
            <param-name>targetBeanName</param-name> 
            <param-value>myFilter</param-value>         //自己过滤器的名字 
        </init-param> 
然后自己可以配置bean id =myFilter的bean即可。下面就是实际的认证授权了待续



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值