`
c04s31602
  • 浏览: 45987 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring Security3学习-过滤器链

 
阅读更多

Spring Security3是目前使用非常广泛的java web安全框架,我经历的项目中有很多在使用它。尽管有shiro等使用更方便、更容易理解、应用范围更广的安全框架开始流行,但Spring Security3在Java web领域无疑是更强大、更容易扩展的。

对Spring Security3配置、应用的blog很多,我就不再介绍这些了。此系列文章主要根据我学习Spring Security3的过程,沿着Filter链介绍Spring Security3的原理。

启用Spring Security3需要做如下三件事

    1、在web.xml配置配置过滤器DelegatingFilterProxy

<filter> 
  <filter-name>springSecurityFilterChain</filter-name> 
  <filterclass> 
    org.springframework.web.filter.DelegatingFilterProxy 
  </filter-class> 
</filter> 
<filter-mapping> 
  <filter-name>springSecurityFilterChain</filter-name> 
  <url-pattern>/*</url-pattern> 
</filter-mapping>

    这里filter的名字必须是springSecurityFilterChain,原因稍后解释。

  2、新建spring-sucirity.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans:beans xmlns="http://www.springframework.org/schema/security" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:beans="http://www.springframework.org/schema/beans" 
       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-3.0.xsd"> 
  <http auto-config="true"> 
    <intercept-url pattern="/*" access="ROLE_USER"/> 
  </http> 
  <authentication-manager alias="authenticationManager"> 
    <authentication-provider> 
      <user-service> 
        <user authorities="ROLE_USER" name="guest" password="guest"/> 
      </user-service> 
    </authentication-provider> 
  </authentication-manager>  
</beans:beans>
    3、添加spring-security.xml到web.xml 
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath*:/spring-security.xml</param-value>
</context-param>

下面开始从入DelegatingFilterProxy手

从名字上可以看出,这个过滤器其实没做什么,只是委派给了其他过滤器。它并不在spring-security包中,而是在spring-web包

 看它的doFilter方法

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		// Lazily initialize the delegate if necessary.
		Filter delegateToUse = null;
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				WebApplicationContext wac = findWebApplicationContext();
				if (wac == null) {
					throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
				}
                                //初始化FilterChain代理
				this.delegate = initDelegate(wac);
			}
			delegateToUse = this.delegate;
		}

		// Let the delegate perform the actual doFilter operation.
                //调用doFilter方法
		invokeDelegate(delegateToUse, request, response, filterChain);
	}

 分析initDelegate方法 

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}
 getTargetBeanName()其实获取到的是Filter名字springSecurityFilterChain:在initFilterBean()方法中对targetBeanName做了赋值
protected void initFilterBean() throws ServletException {
		// If no target bean name specified, use filter name.
		if (this.targetBeanName == null) {
                        //targetBeanName被设置为filterName
			this.targetBeanName = getFilterName();
		}
                ......
	}
 initFilterBean方法在父类GenericFilterBean的init方法中被执行。
这里根据我们在web.xml设置filter的名字去获取Spring Seucurity3的代理过滤器。后面回看到这个名字是springSecurityFilterChain,所以在web.xml的filter名字也必须是这个。
 再分析spring-scurity.xml的解析
org.springframework.security.config.SecurityNamespaceHandler负责解析namespace为security的xml文档,即我们的spring-security.xml文件,它在spring-security-config包:

SecurityNamespaceHandler继承了NamespaceHandler接口,有三个方法:init初始化,parse解析,decorate装饰,在SecurityNamespaceHandler的init方法进行了每个解析类的注册
private void loadParsers() {
        // Parsers
        parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
        parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
        parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
        parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
        parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
        parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
        parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
        parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());

        // Only load the web-namespace parsers if the web classes are available
        if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
            parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
            parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
            parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
            parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
            filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
        }
    }
 HttpSecurityBeanDefinitionParser时解析http节点的解析类
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
 看一下HttpSecurityBeanDefinitionParser是如何解析http节点的,上parse
    public BeanDefinition parse(Element element, ParserContext pc) {
        CompositeComponentDefinition compositeDef =
            new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
        pc.pushContainingComponent(compositeDef);
        final Object source = pc.extractSource(element);

        final String portMapperName = createPortMapper(element, pc);
        final UrlMatcher matcher = createUrlMatcher(element);

        HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);

        httpBldr.parseInterceptUrlsForEmptyFilterChains();
        httpBldr.createSecurityContextPersistenceFilter();
        httpBldr.createSessionManagementFilters();

        ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
        BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);

        httpBldr.createServletApiFilter();
        httpBldr.createChannelProcessingFilter();
        httpBldr.createFilterSecurityInterceptor(authenticationManager);

        AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
                httpBldr.isAllowSessionCreation(), portMapperName);
        //http节点的默认的11个过滤器
        authBldr.createAnonymousFilter();
        authBldr.createRememberMeFilter(authenticationManager);
        authBldr.createRequestCache();
        authBldr.createBasicFilter(authenticationManager);
        authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
        authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
        authBldr.createX509Filter(authenticationManager);
        authBldr.createLogoutFilter();
        authBldr.createLoginPageFilterIfNeeded();
        authBldr.createUserServiceInjector();
        authBldr.createExceptionTranslationFilter();

        List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
        //将过滤器加入过滤器链
        unorderedFilterChain.addAll(httpBldr.getFilters());
        unorderedFilterChain.addAll(authBldr.getFilters());//这里加入的过滤器和我们设置auto-config="true"有关

        authenticationProviders.addAll(authBldr.getProviders());

        BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
        requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());
        unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));

        unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
        //对过滤器进行排序
        Collections.sort(unorderedFilterChain, new OrderComparator());
        checkFilterChainOrder(unorderedFilterChain, pc, source);
        //排好序的过滤器链
        List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();

        for (OrderDecorator od : unorderedFilterChain) {
            filterChain.add(od.bean);
        }

        ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
        filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
        //注册过滤器链proxy
        registerFilterChainProxy(pc, filterChainMap, matcher, source);

        pc.popAndRegisterContainingComponent();
        return null;
    }
    http节点的11个过滤器不是都要加入过滤器链的,这个和我们的auto-config有关。使用auto-config="true"会自动提供以下三个认证相关的功能:
    HTTP基本认证
    Form登录认证
    退出
这一点从源码中可以找到:AuthenticationConfigBuilder类的createLogoutFilter、createBasicFilter和createFormLoginFilter三个方法
void createLogoutFilter() {
        Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
        if (logoutElt != null || autoConfig) {
            logoutFilter = new LogoutBeanDefinitionParser(rememberMeServicesId).parse(logoutElt, pc);
        }
    }
 
void createBasicFilter(BeanReference authManager) {
        ......
        if (basicAuthElt != null || autoConfig) {
            ......
        }
      ......
    }
 
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
      ......
        if (formLoginElt != null || autoConfig) {
          ......
        }
       ......
    }
 可见只有autoConfig=true时才会加入这仨过滤器。
在对unorderedFilterChain进行排序时,这11个过滤器怎么排序的呢?org.springframework.core.OrderComparator的排序逻辑是根据org.springframework.core.Ordered的getOrder方法的比较。在AuthenticationConfigBuilder的getFilters方法返回的事List<OrderDecorator>集合,OrderDecorator的构造方法:
public OrderDecorator(BeanMetadataElement bean, SecurityFilters filterOrder) {
        this.bean = bean;
        this.order = filterOrder.getOrder();
    }
 继续看SecurityFilters枚举类
enum SecurityFilters {
    FIRST (Integer.MIN_VALUE),
    CHANNEL_FILTER,
    CONCURRENT_SESSION_FILTER,
    SECURITY_CONTEXT_FILTER,
    LOGOUT_FILTER,
    X509_FILTER,
    PRE_AUTH_FILTER,
    CAS_FILTER,
    FORM_LOGIN_FILTER,
    OPENID_FILTER,
    LOGIN_PAGE_FILTER,
    DIGEST_AUTH_FILTER,
    BASIC_AUTH_FILTER,
    REQUEST_CACHE_FILTER,
    SERVLET_API_SUPPORT_FILTER,
    REMEMBER_ME_FILTER,
    ANONYMOUS_FILTER,
    SESSION_MANAGEMENT_FILTER,
    EXCEPTION_TRANSLATION_FILTER,
    FILTER_SECURITY_INTERCEPTOR,
    SWITCH_USER_FILTER,
    LAST (Integer.MAX_VALUE);

    private static final int INTERVAL = 100;
    private final int order;

    private SecurityFilters() {
        order = ordinal() * INTERVAL;
    }

    private SecurityFilters(int order) {
        this.order = order;
    }

    public int getOrder() {
       return order;
    }
}
 可见是根据枚举的定义进行排序的,在http节点的配置中,我们将自定一个的过滤器用before、after、position等关键字插入到这11个过滤器前后。
再看注册过滤器链:
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
        if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
            pc.getReaderContext().error("Duplicate <http> element detected", source);
        }
        //定义一个FilterChainProxy
        BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
        fcpBldr.getRawBeanDefinition().setSource(source);
        fcpBldr.addPropertyValue("matcher", matcher);
        fcpBldr.addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
        fcpBldr.addPropertyValue("filterChainMap", filterChainMap);//设置过滤器链集合
        BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
        //注册bean
        pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
        //注册的别名为springSecurityFilterChain,在web.xml配置的filter名也要是这个
        pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
    }
 那么在DelegatingFilterProxy的initDelegate方法就可以获取到这个过滤器链了,然后就是doFilter了。
 
好了,囫囵吞枣的列出这么多,也不是很连贯,但大概应该能说明白原理了。下一篇开始分析过滤器,所以再把过滤器列出来:

过滤器名称

描述

o.s.s.web.context.SecurityContextPersistenceFilter

负责从SecurityContextRepository获取或存储SecurityContext。SecurityContext代表了用户安全和认证过的session。

o.s.s.web.authentication.logout.LogoutFilter

监控一个实际为退出功能的URL(默认为/j_spring_security_logout),并且在匹配的时候完成用户的退出功能。

o.s.s.web.authentication.UsernamePasswordAuthenticationFilter

监控一个使用用户名和密码基于form认证的URL(默认为/j_spring_security_check),并在URL匹配的情况下尝试认证该用户。

o.s.s.web.authentication.ui.DefaultLoginPageGeneratingFilter

监控一个要进行基于forn或OpenID认证的URL(默认为/spring_security_login),并生成展现登录form的HTML

o.s.s.web.authentication.www.BasicAuthenticationFilter

监控HTTP 基础认证的头信息并进行处理

o.s.s.web.savedrequest.

RequestCacheAwareFilter

用于用户登录成功后,重新恢复因为登录被打断的请求。

o.s.s.web.servletapi.

SecurityContextHolderAwareRequest

Filter

用一个扩展了HttpServletRequestWrapper的子类(o.s.s.web. servletapi.SecurityContextHolderAwareRequestWrapper)包装HttpServletRequest。它为请求处理器提供了额外的上下文信息。

o.s.s.web.authentication.

AnonymousAuthenticationFilter

如果用户到这一步还没有经过认证,将会为这个请求关联一个认证的token,标识此用户是匿名的。

o.s.s.web.session.

SessionManagementFilter

根据认证的安全实体信息跟踪session,保证所有关联一个安全实体的session都能被跟踪到。

o.s.s.web.access.

ExceptionTranslationFilter

解决在处理一个请求时产生的指定异常

o.s.s.web.access.intercept.

FilterSecurityInterceptor

简化授权和访问控制决定,委托一个AccessDecisionManager完成授权的判断

 

  • 大小: 20.9 KB
  • 大小: 10.3 KB
分享到:
评论

相关推荐

    spring-security-web源码所需jar包

    《Spring Security Web源码解析与...在Web应用中,Spring Security通过过滤器链来实现安全控制,这些过滤器包括但不限于:`DelegatingRequestMatcherFilter`,`SecurityContextPersistenceFilter`,`LogoutFilter`,`...

    spring-security Jar包

    3. **过滤器链**:Spring Security 的核心是Filter Security Interceptor(过滤器安全拦截器)和Access Decision Manager(访问决策管理器)。过滤器链处理HTTP请求,进行身份验证和授权检查,而访问决策管理器根据...

    spring-security-core-3.1.0.RC1.jar

    3. **Filter Chain**:Spring Security通过一系列过滤器(Filter)实现请求的拦截和处理。在3.1.0.RC1中,这些过滤器如`DelegatingFilterProxy`、`ChannelProcessingFilter`、`SecurityContextPersistenceFilter`等...

    SpringSecurity笔记2-SpringSecurity命名空间

    在"SpringSecurity笔记2-SpringSecurity命名空间"的学习中,还会涉及到如何自定义过滤器链,以及如何通过`&lt;custom-filter&gt;`元素插入自定义的SpringSecurity过滤器。同时,理解`&lt;access-denied-handler&gt;`和`...

    spring security 4.0.0所需jar包

    - `spring-security-web-4.0.0.CI-SNAPSHOT.jar`:处理HTTP请求的安全过滤器,如CSRF防护、登录、注销、会话管理等。 3. **spring-security-config**: - `spring-security-config-4.0.0.CI-SNAPSHOT-javadoc.jar...

    Spring-Security-Demo-master.zip

    8. **自定义过滤器**:在Spring Security中,我们还可以通过添加自定义过滤器来扩展其功能。例如,创建一个实现`FilterSecurityInterceptor`的过滤器,以便在用户请求到达控制器之前进行额外的权限检查。 9. **异常...

    spring-security-core-2.0.5.RELEASE.src

    4. **Filter Chain**:Spring Security的核心在于一系列的过滤器,它们按照预定义的顺序执行,构成Filter Chain。`org.springframework.security.web`包下的Filter如FilterSecurityInterceptor、...

    最详细Spring Security学习资料(源码)

    Spring Security是一个功能强大且高度可定制的身份验证和授权框架,专门用于保护Java应用程序的...Web集成:Spring Security能够无缝集成到Spring框架和Spring MVC中,提供了过滤器、标签库等工具,简化了权限控制和

    SpringSecurity-Jar包

    3. spring-security-web-4.2.3.RELEASE.jar:此模块专注于Web应用的安全需求,提供了一套过滤器链来处理HTTP请求的安全方面。它包含了诸如`FilterSecurityInterceptor`(执行访问决策)和`...

    Spring Security-3中文官方文档(及教程)

    3. **过滤器链**:Spring Security的核心是其过滤器链,包括登录过滤器、CSRF保护、会话管理等。这些过滤器按照特定顺序执行,确保每个请求都经过安全检查。 4. **会话管理**:Spring Security可以实现会话固定保护...

    spring-security-core-2.0.6.RELEASE

    1. **Filter Chain**:Spring Security通过一系列过滤器实现其功能,这些过滤器按照特定顺序组织成一个过滤链。每个过滤器负责处理请求的特定方面,如认证、授权等。 2. **AuthenticationManager**:这是Spring ...

    springsecurity所有jar包

    它提供HTTP安全拦截过滤器链,如`DelegatingFilterProxy`,可以与Spring的DispatcherServlet集成。 4. **spring-security-acl**:这个模块提供了细粒度访问控制,允许对对象级别的权限进行管理。例如,你可以控制...

    spring-security-samples-contacts-2.0.4

    - **Filter Security Interceptor (FSI)**: 一系列Spring MVC过滤器,负责处理HTTP请求的安全性。 - **Security Context**: 存储当前用户的认证信息。 - **Authentication Manager**: 处理身份验证请求,验证用户...

    全面解析Spring Security 过滤器链的机制和特性

    Spring Security 过滤器链机制和特性详解 Spring Security 过滤器链是 Spring Security 框架中的一种核心机制,负责处理 HTTP 请求的安全验证和授权。今天,我们将深入探讨 Spring Security 过滤器链的机制和特性,...

    SpringSecurity3.1.3的jar包

    2. **spring-security-web-3.1.3.RELEASE.jar**:此模块关注于Web安全,提供了过滤器链来处理HTTP请求的安全性。例如,它包含RememberMe服务、HTTP基本和表单登录、CSRF防护以及URL级别的访问控制等功能。 3. **...

    spring-security-oauth2源码

    - **ResourceServerFilter**:资源服务器上的过滤器,验证访问令牌的有效性。 4. **OAuth2的工作流程** 1. 客户端引导用户前往授权服务器进行授权。 2. 用户同意授权后,授权服务器返回授权码或访问令牌。 3. ...

    spring-boot-security

    3. **过滤器链(Filter Chain)**:Spring Security的核心组件之一是过滤器链,它由多个过滤器组成,如`UsernamePasswordAuthenticationFilter`和`HttpSessionAuthenticationStrategy`等。这些过滤器负责处理HTTP...

    spring spring security2.5 jar

    3. **过滤器链**:Spring Security的核心在于其过滤器链,它拦截HTTP请求并应用安全策略。`FilterSecurityInterceptor`是其中的关键组件,负责根据配置的访问规则对请求进行处理。 4. **会话管理**:Spring ...

    Spring-Security-3-HelloWorld 实例简单代码

    Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于Java应用程序...通过逐步学习和实践,可以掌握更复杂的授权策略和高级功能,如角色层次、自定义过滤器、OAuth2整合等,以满足实际项目的需求。

Global site tag (gtag.js) - Google Analytics