知识大全 Spring Security学习总结一

Posted

篇首语:冲天香阵透长安,满城尽带黄金甲。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Spring Security学习总结一相关的知识,希望对你有一定的参考价值。

Spring Security学习总结一  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  在认识Spring Security之前 所有的权限验证逻辑都混杂在业务逻辑中 用户的每个操作以前可能都需要对用户是否有进行该项操作的权限进行判断 来达到认证授权的目的 类似这样的权限验证逻辑代码被分散在系统的许多地方 难以维护 AOP(Aspect Oriented Programming)和Spring Security为我们的应用程序很好的解决了此类问题 正如系统日志 事务管理等这些系统级的服务一样 我们应该将它作为系统一个单独的 切面 进行管理 以达到业务逻辑与系统级的服务真正分离的目的 Spring Security将系统的安全逻辑从业务中分离出来

  本文代码运行环境

  JDK

  spring framework

  spring security

  JavaEE

  Web容器

  Apache Tomcat

  IDE工具

  Eclipse +MyEclipse

  操作系统

  Linux(Fedora )

  这只是我个人的学习总结而已 还请高手们指出本文的不足之处

  一  Spring Security 简介

  这里提到的Spring Security也就是被大家广为熟悉的Acegi Security 年底Acegi Security正式成为Spring Portfolio项目 并更名为Spring Security Spring Security是一个能够为基于Spring的企业应用系统提供描述性安全访问控制解决方案的安全框架 它提供了一组可以在Spring应用上下文中配置的Bean 充分利用了Spring IoC(依赖注入 也称控制反转)和AOP(面向切面编程)功能 为应用系统提供声明式的安全访问控制功能 减少了为企业系统安全控制编写大量重复代码的工作

  通过在许多项目中实践应用以及社区的贡献 如今的Spring Security已经成为Spring Framework下最成熟的安全系统 它为我们提供了强大而灵活的企业级安全服务 如

  Ø         认证授权机制

  Ø          Web资源访问控制

  Ø         业务方法调用访问控制

  Ø         领域对象访问控制Access Control List(ACL)

  Ø         单点登录(Central Authentication Service)

  Ø         X 认证

  Ø         信道安全(Channel Security)管理等功能

  当保护Web资源时 Spring Security使用Servlet 过滤器来拦截Http请求进行身份验证并强制安全性 以确保WEB资源被安全的访问 如下图是Spring Security的主要组件图(摘自《Spring in Action》)

  

  图 Spring Security的基本组件

  无论是保护WEB资源还是保护业务方法或者领域对象 Spring Security都的通过上图中的组件来完成的 本文主要阐述如何使用Spring Security对WEB应用程序的资源进行安全访问控制 并通过一个简单的实例来对Spring Security提供的各种过滤器的功能和配置方法进行描述

  二  保护Web资源

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

  

  过 滤 

  作             

  通道处理过滤器

  确保请求是在安全通道(HTTP和HTTPS)之上传输的

  认证处理过滤器

  接受认证请求 并将它们转交给认证管理器进行身份验证

  CAS处理过滤器

  接受CAS服务票据 验证Yale CAS(单点登录)是否已经对用户进行了认证

  HTTP基本授权过滤器

  处理使用HTTP基本认证的身份验证请求

  集成过滤器

  处理认证信息在请求间的存储(比如在HTTP会话中)

  安全强制过滤器

  确保用户己经认证 并且满足访问一个受保护Web资源的权限需求

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

     建立Spring Security项目

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

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

  

  图 项目目录结构

   配置web xml

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

   <filter>            <filter name>springSecurityFilterChain</filter name>       <filter class>          springframework security util FilterToBeanProxy       </filter class>       <init param>                    <param name>targetClass</param name>           <param value>                            springframework security util FilterChainProxy          </param value>       </init param> </filter>

   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>             <filter name>springSecurityFilterChain</filter name>             <url pattern>/j_spring_security_check</url pattern>          </filter mapping>          <filter mapping>           <filter name>springSecurityFilterChain</filter name>           <url pattern>/*</url pattern>   </filter mapping>

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

   配置applicationContext security xml

   FilterChainProxy过滤器链

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

   <bean id= filterChainProxy             class= springframework security util FilterChainProxy >        <property name= filterInvocationDefinitionSource >           <value><![CDATA[                          CONVERT_URL_TO_LOWERCASE_BEFORE_PARISON                 PATTERN_TYPE_APACHE_ANT                          /**=SessionContextIntegrationFilter logoutFilter                 authenticationProcessingFilter securityContextHolderAwareRequestFilter                 rememberMeProcessingFilter anonymousProcessingFilter exceptionTranslationFilter                 filterSecurityInterceptor            ]]></value>        </property>  </bean>

  CONVERT_URL_TO_LOWERCASE_BEFORE_PARISON 定义URL在匹配之前必须先转为小写 PATTERN_TYPE_APACHE_ANT 定义了使用Apache ant的匹配模式 /**定义的将等号后面的过滤器应用在那些URL上 这里使用全部URL过滤 每个过滤器之间都适用逗号分隔 它们按照一定的顺序排列

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

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

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

 <bean id= SessionContextIntegrationFilter    class= springfrntext HttpSessionContextIntegrationFilter />

  SessionContextIntegrationFilter是集成过滤器的一个实现 在用户的一个请求过程中 用户的认证信息通过SecurityContextHolder(使用ThreadLoacl实现)进行传递的 所有的过滤器都是通过SecurityContextHolder来获取用户的认证信息 从而在一次请求中所有过滤器都能共享Authentication(认证) 减少了HttpRequest参数的传送 下面的代码是从安全上下文的获取Authentication对象的方法

 SecurityContext context = SecurityContextHolder getContext()    Authentication authentication = context getAuthentication();

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

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

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

   <bean id= logoutFilter           class= springframework security ui logout LogoutFilter >          <constructor arg value= /index jsp />          <constructor arg>             <list>               <!  实现了LogoutHandler接口(logout方法)  >               <ref bean= rememberMeServices />               <bean class= springframework security ui logout SecurityContextLogoutHandler />           </list>        </constructor arg>    </bean>

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

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

 <bean id= rememberMeServices              class= springframework security ui rememberme TokenBasedRememberMeServices      p:key= springsecurity     p:userDetailsService ref= userDetailsService />

  TokenBasedRememberMeServices继承自系统的AbstractRememberMeServices抽象类(实现了RememberMeServices和 LogoutHandler两个接口) RememberMeServices接口的loginSuccess方法负责在用户成功登录之后将用户的认证信息存入Cookie中 这个类在后续的过滤器执行过程中也会被用到

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

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

   <bean id= authenticationProcessingFilter           class= springframework security ui webapp AuthenticationProcessingFilter           p:authenticationManager ref= authenticationManager        p:authenticationFailureUrl= /login jsp?login_error=       p:defaultTargetUrl= /default jsp        p:filterProcessesUrl= /j_spring_security_check       p:rememberMeServices ref= rememberMeServices />

  下面列出了认证过程过滤器配置中各个属性的功能

   authenticationManager     认证管理器

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

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

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

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

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

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

   <bean id= authenticationManager       class= springframework security providers ProviderManager     p:sessionController ref= concurrentSessionController >       <property name= providers >          <list>              <ref bean= daoAuthenticationProvider />              <bean     class= springframework security providers anonymous AnonymousAuthenticationProvider                p:key= springsecurity />             <bean    class= springframework security providers rememberme RememberMeAuthenticationProvider                p:key= springsecurity />         </list>      </property>    </bean>

  正如在配置中看到的一样 系统使用 springframework security providers ProviderManager(提供者管理器)类作为认证管理器的一个实现 事实上这个类是继承自实现了AuthenticationManager接口的 AbstractAuthenticationManager类 需要注意的是ProviderManager(提供者管理器)自己并不实现身份验证 而是把这项工作交给了多个认证提供者(提供者集合)或者说的多个认证来源

   提示 Spring Security为我们提供的所有认证提供者实现都是 springframework security providers AuthenticationProvider接口的实现类 它们都实现了此接口的authenticate方法 如果你正在看源代码 会发现这个authenticate方法事实上和AuthenticationManager(认证管理器)接口的authenticate方法完全一样  

  providers属性定义了提供者管理器的集合 ProviderManager(提供者管理器)逐一遍历这个认证提供者的集合并调用提供者的authenticate方法 如果一个提供者认证失败会尝试另外一个提供者直到某一个认证提供者能够成功的验证该用户的身份 以保证获取不同来源的身份认证 下面表格列出了系统提供的一些认证提供者

  

  提   供  

  作            

  DaoAuthenticationProvider

  从数据库中读取用户信息验证身份

  AnonymousAuthenticationProvider

  匿名用户身份认证

  RememberMeAuthenticationProvider

  已存cookie中的用户信息身份认证

  AuthByAdapterProvider

  使用容器的适配器验证身份

  CasAuthenticationProvider

  根据Yale中心认证服务验证身份 用于实现单点登陆

  JaasAuthenticationProvider

  从JASS登陆配置中获取用户信息验证身份

  RemoteAuthenticationProvider

  根据远程服务验证用户身份

  RunAsImplAuthenticationProvider

  对身份已被管理器替换的用户进行验证

  X AuthenticationProvider

  从X 认证中获取用户信息验证身份

  TestingAuthenticationProvider

  单元测试时使用

  从上面的表中可以看出 系统为我们提供了不同的认证提供者 每个认证提供者会对自己指定的证明信息进行认证 如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证

  在实际项目中 用户的身份和权限信息可能存储在不同的安全系统中(如数据库 LDAP服务器 CA中心)

  作为程序员 我们可以根据需要选择不同的AuthenticationProvider(认证提供者)来对自己的系统提供认证服务

  这里我们着重介绍DaoAuthenticationProvider 它从数据库中读取用户信息验证身份 配置如下

 <bean id= daoAuthenticationProvider           class= springframework security providers dao DaoAuthenticationProvider      p:passwordEncoder ref= passwordEncoder     p:userDetailsService ref= userDetailsService />  <bean id= passwordEncoder     class= springframework security providers encoding Md PasswordEncoder />

  还记得前面配置的RememberMeServices吗?它也有一个和DaoAuthenticationProvider同样的属性userDetailsService 这是系统提供的一个接口( springframework security userdetails UserDetailsService) 在这里我们把它单独提出来进行介绍

  首先我们需要了解Spring Security为我们提供的另外一个重要的组件 springframework security userdetails UserDetails接口 它代表一个应用系统的用户 该接口定义与用户安全信息相关的方法

  String getUsername() 获取用户名

  String getPassword() 获取密码

  boolean isAccountNonExpired() 用户帐号是否过期

  boolean isAccountNonLocked() 用户帐号是否锁定

  boolean isCredentialsNonExpired() 用户的凭证是否过期

  boolean isEnabled() 用户是否处于激活状态

  当以上任何一个判断用户状态的方法都返回false时 用户凭证就被视为无效 UserDetails接口还定义了获取用户权限信息的getAuthorities()方法 该方法返回一个GrantedAuthority[]数组对象 GrantedAuthority是用户权限信息对象 这个对象中定义了一个获取用户权限描述信息的getAuthority()方法

  UserDetails即可从数据库中返回 也可以从其它如LDAP中返回 这取决与你的系统中使用什么来存储用户信息和权限以及相应的认证提供者 这里我们只重点介绍DaoAuthenticationProvider(从数据库中获取用户认证信息的提供者) 本人水平有限 在项目中还没有机会用到其它提供者 说到这里 这个封装了用户详细信息的UserDetails该从哪儿获取呢?这就是我们接下来要介绍的UserDetailsService接口 这个接口中只定义了唯一的UserDetails loadUserByUsername(String username)方法 它通过用户名来获取整个UserDetails对象

  看到这里你可能会有些糊涂 因为前面提到的Authentication对象中也存放了用户的认证信息 需要注意Authentication对象才是Spring Security使用的进行安全访问控制用户信息安全对象 实际上 Authentication对象有未认证和已认证两种状态 在作为参数传入认证管理器(AuthenticationManager)的authenticate方法时 是一个未认证的对象 它从客户端获取用户的身份信息(如用户名 密码) 可以是从一个登录页面 也可以从Cookie中获取 并由系统自动构造成一个Authentication对象 而这里提到的UserDetails代表一个用户安全信息的源(从数据库 LDAP服务器 CA中心返回) Spring Security要做的就是将这个未认证的Authentication对象和UserDetails进行匹配 成功后将UserDetails中的用户权限信息拷贝到Authentication中组成一个完整的Authentication对象 共其它组件共享

  这样 我们就可以在系统中获取用户的相关信息了 需要使用到Authentication对象定义的Object getPrincipal()方法 这个方法返回一个Object类型的对象 通常可以将它转换为UserDetails 从而可以获取用户名 密码以及权限等信息 代码如下

 UserDetails details = (UserDetails)authentication getPrincipal();    GrantedAuthority[] authority = details getAuthorities();

  前面介绍了DaoAuthenticationProvider 它可以从数据库中读取用户信息 同样也可以从一个用户属性文件中读取 下一篇文章中我们在介绍如何从数据库中读取用户信息 当然还会涉及到更深入的东西 比如根据自己系统的需要自定义UserDetails和UserDetailsService 这个只是让你对整个系统有个简单的了解 所以我们使用用户属性文件(users properties)来存储用户信息

 admin=admin ROLE_SUPERVISOR    user =user ROLE_USER    user =user ROLE_USER    user =user disabled ROLE_USER

  配置userDetailsService

 <bean id= userDetailsService    class= springframework secumory InMemoryDaoImpl >       <property name= userProperties >          <bean class= springframewonfig PropertiesFactoryBean            p:location= /WEB INF/users properties />       </property> </bean>

  InMemoryDaoImpl类是UserDetailsService接口的一个实现 它从属性文件里读取用户信息 Spring Security使用一个属性编辑器将用户信息为我们组织成一个 springframework secumory UserMap类的对象 我们也可以直接为它提供一个用户权限信息的列表 详见applicationContext security xml配置文件

  UserMap字符串的每一行都用键值对的形式表示 前面是用户名 然后是等号 后面是赋予该用户的密码/权限等信息 它们使用逗号隔开 比如

 admin=admin ROLE_SUPERVISOR

  定义了一个名为admin的用户登录密码为admin 该用户拥有ROLE_SUPERVISOR权限 再如users properties文件中配置的名为user 的用户登录密码为user 该用户拥有ROLE_USER权限 disabled定义该用户不可用 为被激活(UserDetails 的isEnabled方法)

  即使是系统的开发者或者说是最终用户 都不应该看到系统中有明文的密码 所以 Spring Security考虑的还是很周到的 为我们提供的密码加密的功能 正如你在Dao认证提供者(DaoAuthenticationProvider)中看到的 passwordEncoder属性配置的就是一个密码加密程序(密码编码器) 这里我们使用MD 加密 可以看配置文件中的scott用户 你还能看出他的密码是什么吗?当然这里只是演示功能 其它用户还是没有改变 你可以自己试试 系统为我们提供了一些常用的密码编码器(这些编码器都位于 springframework secu rity providers encoding包下)

  PlaintextPasswordEncoder(默认)——不对密码进行编码 直接返回未经改变的密码

  Md PasswordEncoder ——对密码进行消息摘要(MD )编码

  Md PasswordEncoder ——对密码进行消息摘要(MD )编码

  ShaPasswordEncoder ——对密码进行安全哈希算法(SHA)编码

  你可以根据需要选择合适的密码编码器 你也可以设置编码器的种子源(salt source) 一个种子源为编码提供种子(salt) 或者称编码的密钥 这里不再赘述

  这里附加介绍了不少东西 希望你还没有忘记在AuthenticationManager(认证管理器)中还配置了一个名为sessionController的Bean 这个Bean可以阻止用户在进行了一次成功登录以后在进行一次成功的登录 在 applicationContext security xml配置文件添加sessionController的配置

 <bean id= concurrentSessionController    class= springfrncurrent ConcurrentSessionControllerImpl      p:maximumSessions=      p:exceptionIfMaximumExceeded= true      p:sessionRegistry ref= sessionRegistry />  <bean id= sessionRegistry    class= springfrncurrent SessionRegistryImpl />

  maximumSessions属性配置了只允许同一个用户登录系统一次 exceptionIfMaximumExceeded属性配置了在进行第二次登录是是否让第一次登录失效 这里设置为true不允许第二次登录 要让此功能生效 我们还需要在web xml文件中添加一个监听器 以让Spring Security能获取Session的生命周期事件 配置如下

 <listener>       <listener class>          springframework security ui session HttpSessionEventPublisher       </listener class> </listener>

  HttpSessionEventPublisher类实现javax servlet HttpSessionListener接口 在Session被创建的时候通过调用ApplicationContext的publishEvent(ApplicationEvent event)发布HttpSessionCreatedEvent类型的事件 HttpSessionCreatedEvent类继承自ntext ApplicationEvent类的子类 HttpSessionApplicationEvent抽象类

  concurrentSessionController使用sessionRegistry来完成对发布的Session的生命周期事件的处理 springfrncurrent SessionRegistryImpl(实现了SessionRegistry接口) SessionRegistryImpl类还实现了Spring Framework 的事件监听ntext Application Listener接口 并实现了该接口定义的onApplicationEvent(ApplicationEvent event)方法用于处理Applic ationEvent类型的事件 如果你了解Spring Framework的事件处理 那么这里你应该可以很好的理解

  认证管理器到此介绍完毕了 认证过程过滤器也介绍完了 接下来我们继续介绍过滤器链的下一个过滤器securityContextHolderAwareRequestFilter

 <bean id= securityContextHolderAwareRequestFilter     class= springframework security wrapper SecurityContextHolderAwareRequestFilter />

  这个过滤器使用装饰模式(Decorate Model) 装饰的HttpServletRequest对象 其Wapper是ServletRequest包装类HttpServletRequestWrapper的子类(如SavedRequestAwareWrapper或SecurityContextHolderAwareRequestWrapper) 附上获取用户权限信息 request参数 headers 和 cookies 的方法

  rememberMeProcessingFilter过滤器配置

  <bean id= rememberMeProcessingFilter

  class= springframework security ui rememberme RememberMeProcessingFilter

  p authenticationManager ref= authenticationManager

  p rememberMeServices ref= rememberMeServices />

  当SecurityContextHolder中不存在Authentication用户授权信息时 rememberMeProcessingFilter就会调用rememberMeServices 的autoLogin()方法从cookie中获取用户信息自动登录

  anonymousProcessingFilter过滤器配置

 <bean id= anonymousProcessingFilter     class= springframework security providers anonymous AnonymousProcessingFilter      p:key= springsecurity     p:userAttribute= anonymousUser ROLE_ANONYMOUS />

  如果不存在任何授权信息时 自动添加匿名用户身份至SecurityContextHolder中 就是这里配置的userAttribute 系统为用户分配一个ROLE_ANONYMOUS权限

  exceptionTranslationFilter(异常处理过滤器) 该过滤器用来处理在系统认证授权过程中抛出的异常 主要是处理AccessDeniedException和AuthenticationException两个异常并根据配置跳转到不同URL

 <bean id= exceptionTranslationFilter     class= springframework security ui ExceptionTranslationFilter     p:accessDeniedHandler ref= accessDeniedHandler       p:authenticationEntryPoint ref= authenticationEntryPoint />    <!  处理AccessDeniedException  > <bean id= accessDeniedHandler     class= springframework security ui AccessDeniedHandlerImpl      p:errorPage= /accessDenied jsp /> <bean id= authenticationEntryPoint      class= springframework security ui webapp AuthenticationProcessingFilterEntryPoint     p:loginFormUrl= /login jsp     p:forceHttps= false />

  accessDeniedHandler用于处理AccessDeniedException异常 当用户没有权限访问当前请求的资源时抛出此异常 并跳转自这里配置的/accessDenied jsp页面

  authenticationEntryPoint(认证入口点) 这里定义了用户登录的页面 系统为我们提供了 个认证入口点的实现

  

  认 证 入 口 点

  作           用

  BasicProcessingFilterEntryPoint

  通过向浏览器发送一个HTTP (未授权)消息 由浏览器弹出登录对话框 提示用户登录

  AuthenticationProcessingFilterEntryPoint

  将用户重定向到一个基于HTML表单的登录页面

  CasProcessingFilterEntryPoint

  将用户重定向至一个Yale CAS登录页面

  这里我们使用AuthenticationProcessingFilterEntryPoint认证入口点 提供给用户一个友好的登录界面 只是为了给用户更好的体验

  filterSecurityInterceptor(过滤器安全拦截器) 该过滤器首先调用认证管理器来判断用户是否已被成功验证 如果没有被验证则重定向到登录界面 否则 从Authentication获取用户的权限信息 然后从objectDefinitionSource中获取URL所对应的权限 最后调用accessDecisionManager(访问决策管理器)来判断用户当前拥有的权限是否与当前受保护的URL资源对应的权限匹配 如果匹配就可以访问该URL资源 否则将抛出AccessDeniedException异常并返回客户端浏览器一个 错误(如果用户定义了accessDenied页面则会被重定向到该页 见 异常处理过滤器exceptionTranslationFilter中配置的accessDeniedHandler Bean) 访问决策管理的的工作机制将在随后更详细介绍 这里先给出过滤器安全拦截器的配置如下

   <bean id= filterSecurityInterceptor          class= springframework security intercept web FilterSecurityInterceptor          p:authenticationManager ref= authenticationManager          p:accessDecisionManager ref= accessDecisionManager >        <property name= objectDefinitionSource >           <value><![CDATA[         CONVERT_URL_TO_LOWERCASE_BEFORE_PARISON             PATTERN_TYPE_APACHE_ANT             /admins/**=ROLE_SUPERVISOR                    /user/**=ROLE_USER IS_AUTHENTICATED_REMEMBERED                     /default jsp=ROLE_USER IS_AUTHENTICATED_REMEMBERED            /**=IS_AUTHENTICATED_ANONYMOUSLY        ]]></value>      </property> </bean>

  从配置可以看出来 过滤器安全拦截器用到了我们前面配置的认证管理器 过滤器安全拦截器使用authenticationManager并调用它的providers(提供者列表)来对用户的身份进行验证并获取用户拥有的权限 如果用户被成功认证 过滤器安全拦截器将会使用accessDecisionManager(访问决策管理器)来判断已认证的用户是否有权限访问受保护的资源 这些受保护的资源由objectDefinitionSource属性定义

  访问决策管理器(accessDecisionManager)

   <bean id= accessDecisionManager       class= springframework security vote AffirmativeBased         p:allowIfAllAbstainDecisions= false >        <property name= decisionVoters >           <list>              <bean class= springframework security vote RoleVoter />              <bean class= springframework security vote AuthenticatedVoter />           </list>        </property>  </bean>

  身份验证只是Spring Security安全机制的第一步 访问决策管理器验证用户是否有权限访问相应的资源(filterSecurityInterceptor中objectDefinitionSource属性定义的访问URL需要的属性信息)

   springframework security AccessDecisionManager接口定义了用于验证用户是否有权限访问受保护资源的decide方法 另一个supports方法根据受保护资源的配置属性(即访问这些资源所需的权限)来判断该访问决策管理器是否能做出针对该资源的访问决策 decide方法最终决定用户有无访问权限 如果没有则抛出AccessDeniedException异常(面前也提到过 你应该在回过头去看看)

  与认证管理器类似 访问决策管理器也不是由自己来实现访问控制的 而是通过一组投票者来投票决定(通过调用投票者的vote方法) 访问决策管理器统计投票结果并最终完成决策工作 下表列出了系统提供的 个访问决策管理器的实现

  

  访问决策管理器

  如 何 决 策

  AffirmativeBased

  当至少有一个投票者投允许访问票时允许访问

  ConsensusBased

  当所有投票者都投允许访问票时允许访问

  UnanimousBased

  当没有投票者投拒绝访问票时允许访问

  decisionVoters属性为访问决策管理器定义了一组进行投票工作的投票者 那么这些投票者是如何进行投票的呢?这就需要提 springframework security vote AccessDecisionVoter接口 所有的投票者都实现了这个接口并实现了其中的vote方法 该接口中还定义了 个int类型的常量

  int ACCESS_GRANTED = (投赞成票)

  int ACCESS_ABSTAIN = (投弃权票)

  int ACCESS_DENIED = (投反对票)

  每个决策投票者都返回这 个常量中一个 这取决与用户是否有权限访问当前请求的资源 访问决策管理器再对这些投票结果进行统计 认证投票者的配置如上面所示

  loggerListener是一个可选项 它和我们前面配置的Bean或者过滤器没有关系 只是监听系统的一些事件(实现了ApplicationListener监听接口) 被它监听的事件包括AuthenticationCredentialsNotFoundEvent事件 AuthorizationFailureEvent事件 AuthorizedEvent事件 PublicInvocationEvent事件 相信你从他们的名字就能看出来是一些什么样的事件 除非你的e文比我还差劲 loggerListener配置如下

 <bean id= loggerListener  class= springframework security event authentication LoggerListener />

  到此 本例所涉及到的所有配置都介绍完了 在下一篇中会介绍方法安全拦截器 以及如何使用它来保护我们的方法调用 以及前面提到过的会在下一篇中介绍的 这里不在一一列出

  接下来就是JSP页面了 首先是login jsp

   <c:if test= $not empty param login_error >       登录失败 请重试 错误原因:<br/>       <font color= red >           <c:if test= $not empty SPRING_SECURITY_LAST_EXCEPTION >               <c:out value= $SPRING_SECURITY_LAST_EXCEPTION ></c:out>           </c:if>       </font>   </c:if>   <form action= <c:url value= /j_spring_security_check />  method= post >      <table>          <tr>              <td><label for= username >username:</label></td>              <td><input type= text  id= username  name= j_username                     value= <c:out value= $SPRING_SECURITY_LAST_USERNAME /> /></td>          </tr>          <tr>              <td><label for= password >password:</label></td>              <td><input type= password  id= password  name= j_password  value= /></td>          </tr>          <tr><td></td>              <td><input type= checkbox  name= _spring_security_remember_me >两周内记住我</td>          </tr>          <tr><td colspan= ><input type= submit  value= 提交 />          <input type= reset  value= 重置 /></td></tr>      </table>  </form>

  如果你有看源代码 上面的某些参数 以及本文所有提及的东西你都不应该感到陌生 其它页面也不在列出了 还有就是如何让它运行起来 这些我相信你都能自己搞定

  附件 linux/springsecurity rar >springsecurity rar(不包括JAR包)

  补上使用命名空间配置实现的代码 命名空间的详细资料请参考Spring Security中文参考文档 翻译得很好 这里就不在累述了 配置文件中也有比较详细的注释 另外例子中还包括了自定义UserDetailService的实现已经如何Ehcache缓存用户信息 详细的信息将在下一篇中讲述

cha138/Article/program/Java/ky/201311/28455

相关参考

知识大全 Spring Security 2资源-角色查找源码研究及性能改进

SpringSecurity2资源-角色查找源码研究及性能改进  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来

知识大全 spring security3.1 不再支持 filters=none 解决办法

  最近关于springsecurity不再支持filters=none我们有了新的解决办法方法如下  [java]  <security:autoconfig=true>  <!l

知识大全 Spring Integration学习笔记(一)

SpringIntegration学习笔记(一)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 对于Spring初学者的学习建议

对于Spring初学者的学习建议  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!一首先Java的基础

知识大全 Spring柜架基础总结

Spring柜架基础总结  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &n

知识大全 Spring总结实例之消息与事件

Spring总结实例之消息与事件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Spring的消

知识大全 Struts&Spring&Hibernate面试总结

Struts&Spring&Hibernate面试总结  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧

知识大全 Spring 依赖注入原理学习

Spring依赖注入原理学习  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  首先我们来看看Spr

知识大全 Spring自动装配的学习

Spring自动装配的学习  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在xml配置文件中au

知识大全 Spring的IoC学习笔记之BeanFactoryPostProcessor

Spring的IoC学习笔记之BeanFactoryPostProcessor  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,