Spring Security的filter配置及说明

转自:http://zhuoyaopingzi.iteye.com/blog/1219364


以前在PA关注过用户登录授权的过程,看过JAAS的规范,看过WEBLOGIC的实现代码,看过Spring Security的源代码,这么久都忘了。。现在开始,把以前丢掉的技术日记能记得记下来,以后也开始写日记了~~:)

 

----

 

验证

使用opends作ldap数据库,(运行的脚本在该目录的ldap.ldif下)

上下文参数:

http://localhost:389

o=company.com.cn

cn=orcladmin

pwd: hhxxttxs

 



 

创建ou用的opends的图形工具创建,groups下面的条目用ldif导入创建的,ldif如下:

dn:cn=staffRole,ou=groups,o= company.com.cn

objectClass:groupOfUniqueNames

cn:staffRole

uniquemember:uid=zhuoyueping790,ou=staff,ou=people,o= company.com.cn

 

dn:cn=clientRole,ou=groups,o= company.com.cn

objectClass:groupOfUniqueNames

cn:clientRole

uniquemember:uid=chenshengli532,ou=client,ou=people,o= company.com.cn

有staffRole角色的用户可以访问/staff.*资源;

有clientRole角色的用户可以访问/client.*资源

 

例子中所有密码均为:hhxxttxs

所有标有页数的地方为《敏捷Acegi、CAS——构建安全的java系统》的页码。

红色表示待解决的问题,蓝色表示有特别说明或者代码解释的语句。

该项目的全部文件(包括jar包,在该目录下的ss目录中)

斜体bena的名字表示即将要解释的调用的bean.

web.xml

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee

    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 

    Contacts Sample Application

   

        contextConfigLocation

        /WEB-INF/applicationContextsecurity.xml

   

   

   

      

           org.springframework.web.context.ContextLoaderListener《1》

      

      

   

       springSecurityFilterChain

      

           org.springframework.security.util.FilterToBeanProxy《2》

      

      

           targetBean

           filterChainProxy

      

   

 

   

        springSecurityFilterChain

        /*

   

 

   

        springSecurityFilterChain

        /j_spring_security_check

   

   

        index.jsp

   

 

《1》:org.springframework.web.context.ContextLoaderListener

(该类在spring-web.jar包中,)

《2》:org.springframework.util.FilterToBeanProxy:如果配置了targetBean和targetClass,优先调用targetHean.推荐使用targetHean的方式。

通过调用FilterToBeanProxy的init()方法启动过滤器链工作。

(org.springframework.security.*的类都在spring-security-core.jar包中,)

 

public class FilterToBeanProxy implements Filter{

public void init(FilterConfig filterConfig) throws ServletException {

    this.filterConfig = filterConfig;

    String strategy = filterConfig.getInitParameter("init");

    if ((strategy != null) && (strategy.toLowerCase().equals("lazy"))) {

      return;

   }

    doInit();

  }

}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

   throws IOException, ServletException

  {

     if (!(this.initialized)) {

       doInit();

     }

}

 

private synchronized void doInit() throws ServletException {

//…

    String targetBean = this.filterConfig.getInitParameter("targetBean");

//关于lifecircle部分,先放在这里以后补充  

String lifecycle = this.filterConfig.getInitParameter("lifecycle");

    if ("servlet-container-managed".equals(lifecycle)) {

      this.servletContainerManaged = true;

    }

    ApplicationContext ctx = getContext(this.filterConfig);

String beanName = null;

 

   if ((targetBean != null) && (ctx.containsBean(targetBean))) {

     beanName = targetBean;

    }

  else

  {

       Class targetClass;

      if (targetBean != null) {

       throw new ServletException("targetBean '" + targetBean + "' not found in context");

      }

      String targetClassString = this.filterConfig.getInitParameter("targetClass");

//…      

targetClass= Thread.currentThread().getContextClassLoader().loadClass(targetClassString);

//..

     this.initialized = true;

//得到代理类,代理类必须是filter类,调用代理类的init()

Object object = ctx.getBean(beanName);

if (!(object instanceof Filter)) {

      throw new ServletException("Bean '" + beanName + "' does not implement javax.servlet.Filter");

     }

    this.delegate = ((Filter)object);

   if (this.servletContainerManaged) {

 

//启动代理filter的init方法

     this.delegate.init(this.filterConfig);

     }

  }

 

 

/WEB-INF/applicationContextsecurity.xml:

配置bean:filterChainProxy

        class="org.springframework.security.util.FilterChainProxy">《3》

        《4》

           

                PATTERN_TYPE_APACHE_ANT     /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor

           

       

《4》给该参数配置过滤器链。

《3》org.springframework.security.util.FilterChainProxy

/**表示要过该链的url为all

public class FilterChainProxy  implements Filter, InitializingBean, ApplicationContextAware{

public void init(FilterConfig filterConfig) throws ServletException

  {

   Filter[] filters = obtainAllDefinedFilters();

    for (int i = 0; i < filters.length; ++i)

           filters[i].init(filterConfig);//依次调用每个filter的过滤器链

      }

  }

}

//destroy也相同,调用每个filter的destroy

 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

    throws IOException, ServletException

   {

   FilterInvocation fi = new FilterInvocation(request, response, chain);

    List filters = getFilters(fi.getRequestUrl());

    if ((filters == null) || (filters.size() == 0)) {

        chain.doFilter(request, response);

      return;

}

virtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters, null);

virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());

}

}

 

下面依次是过滤器链中的过滤器。

 

配置bean:httpSessionContextIntegrationFilter

集成过滤器,P49,如名字所示,将httpSession与securityContext中的认证信息同步。

      

       class="org.springframework.security.context.HttpSessionContextIntegrationFilter">5

              allowSessionCreation" value="false" />6

      

5》HttpSessionContextIntegrationFilter继承SpringSecurityFilter,SpringSecurityFilter实现了接口filter,在SpringSecurityFilter【附1】的doFilter方法中调用了doFilterHttp,子类在doFilterHttp中实现自己的逻辑,该过滤器应该放在所有过滤器之前。

6allowSessionCreation 是否创建HTTP session。

public class HttpSessionContextIntegrationFilter extends SpringSecurityFilter

 implements InitializingBean{

public void doFilterHttp(HttpServletRequest request, HttpServletResponse response,

FilterChain chain){

public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)  throws IOException, ServletException

{

//进入该过滤器器,从session中取认证相关信息,放在SecurityContext中。

SecurityContext contextBeforeChainExecution = readSecurityContextFromSession(httpSession);

SecurityContextHolder.setContext(contextBeforeChainExecution);

 //继续执行过滤器链,因此,该过滤器应该放在所有过滤器之前!

chain.doFilter(request, responseWrapper);

 

//…

//在finally中执行,退出出这个过滤器(也是该过滤器链执行完后)前执行。

//在contextAfterChainExecution存最新的SecurityContext

SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();

 

SecurityContextHolder.clearContext();//清除当前线程中的SecurityContext相关信息。

request.removeAttribute("__spring_security_session_integration_filter_applied");

//将contextAfterChainExecution 修改过的securitycontext放在HTTP session对象中

if (!(responseWrapper.isSessionUpdateDone())) {

storeSecurityContextInSession(contextAfterChainExecution, request,

httpSessionExistedAtStartOfRequest,

contextHashBeforeChainExecution);

     }

}

}

 

 

 

配置bean:authenticationProcessingFilter

*认证处理过滤器。

      

              class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">

             

                    

             

             

                     /login.jsp?login_error=1

             

             

                     /

             

             

                     /j_spring_security_check

             

      

org.springframework.security.ui.webapp.AuthenticationProcessingFilter

表示用表单认证的类;

authenticationFailureUrl:认证失败跳转的url

defaultTargetUrl:认证完成后,跳转回之前请求的页面,如果没有,到该url

filterProcessesUrl:提交验证请求的form标签中action的地址

authenticationManager:处理得到的用户名和密码交给谁验证的问题 -->

 

      

              class="org.springframework.security.providers.ProviderManager">p50

             

                    

                           

                    

             

      

 

providers:可以指定多个provider bean

 -->

 

              class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">

             

             

org.springframework.security.providers.ldap.LdapAuthenticationProvider

指定该bean是去ldap认证。

:ldap中哪里找用户

:用什么来查,在哪里查角色

 -->

      

              class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">

             

             

                    

                            uid={0},ou=users

                    

             

             

                     ref="ldapUserDetailsMapper">

             

      

—initialDirContextFactory有错,主要原因是包的依赖关系有问题,待解决。 -->

 

       initialDirContextFactory"

              class="org.springframework.security.ldap.DefaultInitialDirContextFactory">

             

             

             

             

             

             

                     value="com.sun.jndi.ldap.LdapCtxFactory" />

      

      

              class="org.springframework.security.userdetails.ldap.LdapUserDetailsMapper">

             

             

              p236:将该参数的值作为role,如:ROLE_CN

                    

                            cn

                    

             

             

      

      

      

 

      

       class="org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">

             

             

             

             

             

             

             

             

      

 

 

 

配置bean:exceptionTranslationFilter

异常处理器:处理认证和授权过程中的异常

      

              class="org.springframework.security.ui.ExceptionTranslationFilter">

             

                    

             

      

 p173-->

 

      

       class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">

             

                     /login.jsp

             

      

继承自AuthenticationEntryPoint p17

AuthenticationEntryPoint commence(ServletRequest request, ServletResponse response, AuthenticationException authException) 构造验证入口。

-->

 

 

 

配置bean:filterInvocationInterceptor

过滤安全拦截器:处理认证和授权过程中的异常

 

      

              class="org.springframework.security.intercept.web.FilterSecurityInterceptor">

             

                    

             

             

                    

             

             

                    

                            PATTERN_TYPE_APACHE_ANT /client/*=ROLE_CLIENTROLE

                            /staff/*=ROLE_staffRole

                    

             

      

 

      

              class="org.springframework.security.vote.AffirmativeBased">

             

                     false

             

             

                    

                           

                    

             

      

 

 

      

              class="org.springframework.security.vote.RoleVoter" />

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

附:一些类。

附1:

public abstract class SpringSecurityFilter implements Filter, Ordered

{

protected final Log logger;

  public SpringSecurityFilter()

   {

    this.logger = LogFactory.getLog(super.getClass());

   }

public final void init(FilterConfig filterConfig)

   throws ServletException

  {

  }

  public final void destroy()

  {

  }

   public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)    throws IOException, ServletException

  {

   if (!(request instanceof HttpServletRequest)) {

      throw new ServletException("Can only process HttpServletRequest");

    }

    if (!(response instanceof HttpServletResponse)) {

      throw new ServletException("Can only process HttpServletResponse");

    }

   doFilterHttp((HttpServletRequest)request, (HttpServletResponse)response, chain);

  }

  protected abstract void doFilterHttp(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse, FilterChain paramFilterChain) throws IOException, ServletException;

  public String toString() {

    return super.getClass() + "[ order=" + super.getOrder() + "; ]";

  }

public abstract int getOrder();

}

 

 

 

/WEB-INF/applicationContextsecurity.xml

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:jee="http://www.springframework.org/schema/jee"

    xmlns:jms="http://www.springframework.org/schema/jms"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd

        http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd

        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

 

   

   

        class="org.springframework.security.context.HttpSessionContextIntegrationFilter">

       

   

 

 

    下一个bean(initialDirContextFactory)有错,主要原因是包的依赖关系有问题,待解决。 -->

       

    initialDirContextFactory"

        class="org.springframework.security.ldap.DefaultInitialDirContextFactory">

       

       

       

       

       

       

            value="com.sun.jndi.ldap.LdapCtxFactory" />

   

 

   

   

       

       

       

           

                cn

           

       

       

   

   

   

       

       

           

                uid={0},ou=users

           

       

       

            ref="ldapUserDetailsMapper">

       

   

 

   

   

 

   

       

       

   

 

   

        class="org.springframework.security.providers.ProviderManager">

       

           

               

           

       

   

 

   

   

       

           

       

       

            /login.jsp?login_error=1

       

       

            /

       

       

            /j_spring_security_check

       

   

 

   

   

   

       

            /login.jsp

       

   

 

   

   

        class="org.springframework.security.ui.ExceptionTranslationFilter">

       

           

       

   

 

   

       

       

       

       

       

       

       

       

   

 

   

 

   

        class="org.springframework.security.vote.RoleVoter" />

 

   

        class="org.springframework.security.vote.AffirmativeBased">

       

            false

       

       

           

               

           

       

   

 

   

        class="org.springframework.security.intercept.web.FilterSecurityInterceptor">

       

           

       

       

           

       

       

           

                PATTERN_TYPE_APACHE_ANT /client/*=ROLE_CLIENTROLE

                /staff/*=ROLE_staffRole

           

       

   

 

 

   

        class="org.springframework.security.util.FilterChainProxy">

       

           

                PATTERN_TYPE_APACHE_ANT

                /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor

           

       

   

 

 



你可能感兴趣的:(Spring Security的filter配置及说明)