Spring Security使用总结(基础部分)

二 保护Web资源

    Spring Security提供了很多的过滤器,它们拦截Servlet请求,并将这些请求转交给认证处理过滤器和访问决策过滤器进行处理,并强制安全性,认证用户身份和用户权限以达到保护Web资源的目的。对于Web资源我们大约可以只用6个过滤器来保护我们的应用系统,下表列出了这些安全过滤器的名称作用以及它们在系统中的执行顺序:

过 滤 器
 作               用
 
通道处理过滤器
 确保请求是在安全通道(HTTP和HTTPS)之上传输的
 
认证处理过滤器
 接受认证请求,并将它们转交给认证管理器进行身份验证
 
CAS 处理过滤器
 接受CAS服务票据,验证Yale CAS(单点登录)是否已经对用户进行了认证
 
HTTP 基本授权过滤器
 处理使用HTTP基本认证的身份验证请求
 
集成过滤器
 处理认证信息在请求间的存储 (比如在HTTP会话中)
 
安全强制过滤器
 确保用户己经认证,并且满足访问一个受保护Web资源的权限需求
 


    接下来,通过一个实例来说明它们的具体使用方法和如何在Spring中进行配置。

    1 建立Spring Security项目

    首先在MyEclipse中创建一个Web Project,并使用MyEclipse工具导入Spring项目的依赖JAR包,并生成默认的,这里暂时不会用到这个文件,本文只是通过一个简单的实例来说明如何配置使用Spring Security,不会涉及到数据库,而是使用一个用户属性(users.properties)文件来保存用户信息(包括用户名,密码及相应的权限),但在实际的项目中,我们很少会这样做,而是应该把用户信息存在数据库中,下一篇文章中将会详细介绍并用到这个文件来配置Hibernate,这里我们保留它。

    现在还需要为项目导入Spring Security的JAR包,它没有包括在Spring Framework中,你可以从http://www.springframework.org/download/ 下载 ,并将spring-security-core-2.0.0.jar(这是核心代码库)和spring-security-core-tiger- 2.0.0.jar(和annotation有关的,比如使用注解对方法进行安全访问控制,在下一篇中会用到)拷贝到项目的lib目录下,其中也包括两个实例(tutorial和contacts),并且两个实例中都包括了如何使用Spring 2.0的命名空间来配置Spring Security,无论你对Spring 2.0命名空间的使用是否了解,它将使我们的配置文件大大缩短,简化开发,提高生产效率。到此,我们的Spring Security项目就建好了,项目目录结构如下图所示:

 

    图2 项目目录结构

    2 配置web.xml

    Spring Security使用一组过滤器链来对用户进行身份验证和授权。首先,在web.xml文件中添加FilterToBeanProxy过滤器配置:

1 < filter >    
2       < filter-name > springSecurityFilterChain </ filter-name >
3      < filter-class >
4         org.springframework.security.util.FilterToBeanProxy
5      </ filter-class >
6      < init-param >        
7         < param-name > targetClass </ param-name >
8          < param-value >            
9             org.springframework.security.util.FilterChainProxy
10          </ param-value >
11      </ init-param >
12 </ filter >
13
    org.springframework.security.util.FilterToBeanProxy实现了Filter接口,它通过调用 WebapplicationContextUtils类的getWebApplicationnContext(servletContext)方法来获取Spring的应用上下文句柄,并通过getBean(beanName)方法来获取Spring受管Bean的对象,即这里targetClass 参数配置的Bean,并通过调用FilterChain Proxy的init()方法来启动Spring Security过滤器链进行各种身份验证和授权服务(FilterChainProxy类也是实现了Filter接口),从而将过滤功能委托给 Spring的FilterChainProxy受管Bean(它维护着一个处理验证和授权的过滤器列表,列表中的过滤器按照一定的顺序执行并完成认证过程),这样即简化了web.xml文件的配置,又能充分利用 Spring的IoC功能来完成这些过滤器执行所需要的其它资源的注入。

    当用户发出请求,过滤器需要根据web.xml配置的请求映射地址来拦截用户请求,这时Spring Security开始工作,它会验证你的身份以及当前请求的资源是否与你拥有的权限相符,从而达到保护Web资源的功能,下面是本例所要过滤的用户请求地址:

< filter-mapping >
2
3         < filter-name > springSecurityFilterChain </ filter-name >
4
5         < url-pattern > / j_spring_security_check </ url-pattern >
6
7      </ filter-mapping >
8
9      < filter-mapping >
10
11         < filter-name > springSecurityFilterChain </ filter-name >
12
13         < url-pattern > /* </ url-pattern >
14
15 </ filter-mapping >

提示:
/j_spring_security_check是Spring Security默认的进行表单验证的过滤地址,你也可以修改为别的名称,但是需要和
applicationContext-security.xml中相对应,当然还会涉及到其它一些默认值(可能是一个成员变量,也可能是别的请
求地址),在下文我们将看到,建议你在阅读此文的同时,应该参照Spring Security项目的源代码,便于你更好的理解。
 


3 配置applicationContext-security.xml

    3.1 FilterChainProxy过滤器链

    FilterChainProxy会按顺序来调用一组filter,使这些filter即能完成验证授权的本质工作,又能享用Spring Ioc的功能来方便的得到其它依赖的资源。FilterChainProxy配置如下:

1 < bean id ="filterChainProxy"    
        class ="org.springframework.security.util.FilterChainProxy" >
2       < property name ="filterInvocationDefinitionSource" >
3          < value > <![CDATA[          
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
4              PATTERN_TYPE_APACHE_ANT         
                /**=httpSessionContextIntegrationFilter,logoutFilter,
5              authenticationProcessingFilter,securityContextHolderAwareRequestFilter,
6              rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,
7              filterSecurityInterceptor
8          ]]> </ value >
9       </ property >
10 </ bean >
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 定义URL在匹配之前必须先转为小写,PATTERN_TYPE_APACHE_ANT 定义了使用Apache ant的匹配模式,/**定义的将等号后面的过滤器应用在那些URL上,这里使用全部URL过滤,每个过滤器之间都适用逗号分隔,它们按照一定的顺序排列。

提示:
特别需要注意的是,即使你配置了系统提供的所有过滤器,这个过滤器链会很长,但是千万不要使用换行,否则它们不会正常工作,
容器甚至不能正常启动。
 


    下面根据FilterChainProxy的配置来介绍各个过滤器的配置,各个过滤器的执行顺序如以上配置。

    首先是通道处理过滤器,如果你需要使用HTTPS,这里我们就使用HTTP进行传输,所以不需要配置通道处理过滤器,然后是集成过滤器,配置如下:

1 < bean id ="httpSessionContextIntegrationFilter"
2
3 class ="org.springframework.security.context.HttpSessionContextIntegrationFilter" />
    httpSessionContextIntegrationFilter是集成过滤器的一个实现,在用户的一个请求过程中,用户的认证信息通过 SecurityContextHolder(使用ThreadLoacl实现)进行传递的,所有的过滤器都是通过 SecurityContextHolder来获取用户的认证信息,从而在一次请求中所有过滤器都能共享Authentication(认证),减少了 HttpRequest参数的传送,下面的代码是从安全上下文的获取Authentication对象的方法:

1 SecurityContext context = SecurityContextHolder.getContext();
2
3 Authentication authentication = context.getAuthentication();
    但是,ThreadLoacl不能跨越多个请求存在,所以,集成过滤器在请求开始时从Http会话中取出用户认证信息并创建一个 SecurityContextHolder将Authentication对象保存在其中,在请求结束之后,在从 SecurityContextHolder中获取Authentication对象并将其放回Http会话中,共下次请求使用,从而达到了跨越多个请求的目的。集成过滤器还有其它的实现,可以参考相关文档。

提示:
集成过滤器必须在其它过滤器之前被使用。
 


    logoutFilter(退出过滤器) ,退出登录操作:

1 < bean id ="logoutFilter"
2
3      class ="org.springframework.security.ui.logout.LogoutFilter" >
4
5      < constructor-arg value ="/index.jsp" />
6
7      < constructor-arg >
8
9         < list >
10
11             <!-- 实现了LogoutHandler接口(logout方法) -->
12
13             < ref bean ="rememberMeServices" />
14
15             < bean class ="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />
16
17         </ list >
18
19      </ constructor-arg >
20
21 </ bean >
 

LogoutFilter的构造函数需要两个参数,第一个是退出系统后系统跳转到的URL,第二个是一个LogoutHandler类型的数组,这个数组里的对象都实现了LogoutHandler接口,并实现了它的logout方法,用户在发送退出请求后,会一次执行LogoutHandler数组的对象并调用它们的 logout方法进行一些后续的清理操作,主要是从SecurityContextHolder对象中清楚所有用户的认证信息(Authentication对象),将用户的会话对象设为无效,这些都时由SecurityContextLogoutHandler来完成。 LogoutFilter还会清除Cookie记录,它由另外一个Bean来完成(RememberMeServices)。

    <ref bean="rememberMeServices"/>标记指向了我们另外配置的一个Bean:

1 < bean id ="rememberMeServices"     
        class ="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices"
2      p:key ="springsecurity"
3     p:userDetailsService-ref ="userDetailsService" />
    TokenBasedRememberMeServices继承自系统的AbstractRememberMeServices抽象类(实现了 RememberMeServices和 LogoutHandler两个接口), RememberMeServices接口的loginSuccess方法负责在用户成功登录之后将用户的认证信息存入Cookie中,这个类在后续的过滤器执行过程中也会被用到。

    另一个userDetailsService属性也是指向了我们配置的Bean, 它负责从数据库中读取用户的信息,这个类的详细配置将在后面的部分详细介绍,这里只是简单的认识一下。

    过滤器链的下个配置的过滤器是authenticationProcessingFilter(认证过程过滤器),我们使用它来处理表单认证,当接受到与filterProcessesUrl所定义相同的请求时它开始工作:

1 < bean id ="authenticationProcessingFilter"
2
3      class ="org.springframework.security.ui.webapp.AuthenticationProcessingFilter"
4
5      p:authenticationManager-ref ="authenticationManager"
6      p:authenticationFailureUrl ="/login.jsp?login_error=1"
7     p:defaultTargetUrl ="/default.jsp"
8     p:filterProcessesUrl ="/j_spring_security_check"
9     p:rememberMeServices-ref ="rememberMeServices" />
    下面列出了认证过程过滤器配置中各个属性的功能:

    1.authenticationManager     认证管理器

    2.authenticationFailureUrl 定义登录失败时转向的页面

    3.defaultTargetUrl         定义登录成功时转向的页面

    4.filterProcessesUrl        定义登录请求的地址(在web.xml中配置过)

    5.rememberMeServices        在验证成功后添加cookie信息

    这里也用到了rememberMeServices,如果用户认证成功,将调用RememberMeServices的loginSuccess方法将用户认证信息写入Cookie中,这里也可以看到使用IoC的好处。

    决定用户是否有权限访问受保护资源的第一步就是要确定用户的身份,最常用的方式就是用户提供一个用户名和密码以确认用户的身份是否合法,这一步就是由认证过程过滤器调用authenticationManager(认证管理器)来完成的。 org.springframework.security.AuthenticationManager接口定义了一个authenticate方法,它使用Authentication作为入口参数(只包含用户名和密码),并在验证成功后返回一个完整的Authentication对象(包含用户的权限信息GrantedAuthority数组对象),authenticationProcessingFilter(认证过程过滤器)会将这个完整的 Authentication对象存入SecurityContext中,如果认证失败会抛出一个AuthenticationException并跳转到authenticationFailureUrl 定义的URL.认证管理其配置如下:

1 < bean id ="authenticationManager"
2
3 class ="org.springframework.security.providers.ProviderManager"
4 p:sessionController-ref ="concurrentSessionController" >
5      < property name ="providers" >
6         < list >
7             < ref bean ="daoAuthenticationProvider" />
8             < bean
9
10 class ="org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider"
11                p:key ="springsecurity" />
12             < bean
13
14 class ="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider"
15                p:key ="springsecurity" />
16         </ list >
17      </ property >  
18 </ bean >

 

< filter-mapping >
2
3         < filter-name > springSecurityFilterChain </ filter-name >
4
5         < url-pattern > /j_spring_security_check </ url-pattern >
6
7      </ filter-mapping >
8
9      < filter-mapping >
10
11         < filter-name > springSecurityFilterChain </ filter-name >
12
13         < url-pattern > /* </ url-pattern >
14
15 </ filter-mapping >
提示:
/j_spring_security_check是Spring Security默认的进行表单验证的过滤地址,你也可以修改为别的名称,但是需要和
applicationContext-security.xml中相对应,当然还会涉及到其它一些默认值(可能是一个成员变量,也可能是别的请
求地址),在下文我们将看到,建议你在阅读此文的同时,应该参照Spring Security项目的源代码,便于你更好的理解。
 


3 配置applicationContext-security.xml

    3.1 FilterChainProxy过滤器链

    FilterChainProxy会按顺序来调用一组filter,使这些filter即能完成验证授权的本质工作,又能享用Spring Ioc的功能来方便的得到其它依赖的资源。FilterChainProxy配置如下:

1 < bean id ="filterChainProxy"    
        class ="org.springframework.security.util.FilterChainProxy" >
2       < property name ="filterInvocationDefinitionSource" >
3          < value > <![CDATA[          
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
4              PATTERN_TYPE_APACHE_ANT         
                /**=httpSessionContextIntegrationFilter,logoutFilter,
5              authenticationProcessingFilter,securityContextHolderAwareRequestFilter,
6              rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,
7              filterSecurityInterceptor
8          ]]> </ value >
9       </ property >
10 </ bean >
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 定义URL在匹配之前必须先转为小写,PATTERN_TYPE_APACHE_ANT 定义了使用Apache ant的匹配模式,/**定义的将等号后面的过滤器应用在那些URL上,这里使用全部URL过滤,每个过滤器之间都适用逗号分隔,它们按照一定的顺序排列。

提示:
特别需要注意的是,即使你配置了系统提供的所有过滤器,这个过滤器链会很长,但是千万不要使用换行,否则它们不会正常工作,
容器甚至不能正常启动。
 


    下面根据FilterChainProxy的配置来介绍各个过滤器的配置,各个过滤器的执行顺序如以上配置。

    首先是通道处理过滤器,如果你需要使用HTTPS,这里我们就使用HTTP进行传输,所以不需要配置通道处理过滤器,然后是集成过滤器,配置如下:

1 < bean id ="httpSessionContextIntegrationFilter"
2
3 class ="org.springframework.security.context.HttpSessionContextIntegrationFilter" />
    httpSessionContextIntegrationFilter是集成过滤器的一个实现,在用户的一个请求过程中,用户的认证信息通过 SecurityContextHolder(使用ThreadLoacl实现)进行传递的,所有的过滤器都是通过 SecurityContextHolder来获取用户的认证信息,从而在一次请求中所有过滤器都能共享Authentication(认证),减少了 HttpRequest参数的传送,下面的代码是从安全上下文的获取Authentication对象的方法:

1 SecurityContext context = SecurityContextHolder.getContext();
2
3 Authentication authentication = context.getAuthentication();
    但是,ThreadLoacl不能跨越多个请求存在,所以,集成过滤器在请求开始时从Http会话中取出用户认证信息并创建一个 SecurityContextHolder将Authentication对象保存在其中,在请求结束之后,在从 SecurityContextHolder中获取Authentication对象并将其放回Http会话中,共下次请求使用,从而达到了跨越多个请求的目的。集成过滤器还有其它的实现,可以参考相关文档。

提示:
集成过滤器必须在其它过滤器之前被使用。
 


    logoutFilter(退出过滤器) ,退出登录操作:

1 < bean id ="logoutFilter"
2
3      class ="org.springframework.security.ui.logout.LogoutFilter" >
4
5      < constructor-arg value ="/index.jsp" />
6
7      < constructor-arg >
8
9         < list >
10
11             <!-- 实现了LogoutHandler接口(logout方法) -->
12
13             < ref bean ="rememberMeServices" />
14
15             < bean class ="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />
16
17         </ list >
18
19      </ constructor-arg >
20
21 </ bean >
 

LogoutFilter的构造函数需要两个参数,第一个是退出系统后系统跳转到的URL,第二个是一个LogoutHandler类型的数组,这个数组里的对象都实现了LogoutHandler接口,并实现了它的logout方法,用户在发送退出请求后,会一次执行LogoutHandler数组的对象并调用它们的 logout方法进行一些后续的清理操作,主要是从SecurityContextHolder对象中清楚所有用户的认证信息(Authentication对象),将用户的会话对象设为无效,这些都时由SecurityContextLogoutHandler来完成。 LogoutFilter还会清除Cookie记录,它由另外一个Bean来完成(RememberMeServices)。

    <ref bean="rememberMeServices"/>标记指向了我们另外配置的一个Bean:

1 < bean id ="rememberMeServices"     
        class ="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices"
2      p:key ="springsecurity"
3     p:userDetailsService-ref ="userDetailsService" />
    TokenBasedRememberMeServices继承自系统的AbstractRememberMeServices抽象类(实现了 RememberMeServices和 LogoutHandler两个接口), RememberMeServices接口的loginSuccess方法负责在用户成功登录之后将用户的认证信息存入Cookie中,这个类在后续的过滤器执行过程中也会被用到。

    另一个userDetailsService属性也是指向了我们配置的Bean, 它负责从数据库中读取用户的信息,这个类的详细配置将在后面的部分详细介绍,这里只是简单的认识一下。

    过滤器链的下个配置的过滤器是authenticationProcessingFilter(认证过程过滤器),我们使用它来处理表单认证,当接受到与filterProcessesUrl所定义相同的请求时它开始工作:

1 < bean id ="authenticationProcessingFilter"
2
3      class ="org.springframework.security.ui.webapp.AuthenticationProcessingFilter"
4
5      p:authenticationManager-ref ="authenticationManager"
6      p:authenticationFailureUrl ="/login.jsp?login_error=1"
7     p:defaultTargetUrl ="/default.jsp"
8     p:filterProcessesUrl ="/j_spring_security_check"
9     p:rememberMeServices-ref ="rememberMeServices" />
    下面列出了认证过程过滤器配置中各个属性的功能:

    1.authenticationManager     认证管理器

    2.authenticationFailureUrl 定义登录失败时转向的页面

    3.defaultTargetUrl         定义登录成功时转向的页面

    4.filterProcessesUrl        定义登录请求的地址(在web.xml中配置过)

    5.rememberMeServices        在验证成功后添加cookie信息

    这里也用到了rememberMeServices,如果用户认证成功,将调用RememberMeServices的loginSuccess方法将用户认证信息写入Cookie中,这里也可以看到使用IoC的好处。

    决定用户是否有权限访问受保护资源的第一步就是要确定用户的身份,最常用的方式就是用户提供一个用户名和密码以确认用户的身份是否合法,这一步就是由认证过程过滤器调用authenticationManager(认证管理器)来完成的。 org.springframework.security.AuthenticationManager接口定义了一个authenticate方法,它使用Authentication作为入口参数(只包含用户名和密码),并在验证成功后返回一个完整的Authentication对象(包含用户的权限信息GrantedAuthority数组对象),authenticationProcessingFilter(认证过程过滤器)会将这个完整的 Authentication对象存入SecurityContext中,如果认证失败会抛出一个AuthenticationException并跳转到authenticationFailureUrl 定义的URL.认证管理其配置如下:

1 < bean id ="authenticationManager"
2
3 class ="org.springframework.security.providers.ProviderManager"
4 p:sessionController-ref ="concurrentSessionController" >
5      < property name ="providers" >
6         < list >
7             < ref bean ="daoAuthenticationProvider" />
8             < bean
9
10 class ="org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider"
11                p:key ="springsecurity" />
12             < bean
13
14 class ="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider"
15                p:key ="springsecurity" />
16         </ list >
17      </ property >  
18 </ bean >

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值