提示: Spring Security为我们提供的所有认证提供者实现都是org.springframework.security.providers .AuthenticationProvider 接口的实现类,它们都实现了此接口的authenticate方法,如果你正在看源代码,会发现这个authenticate方法事实上和Authe nticationManager(认证管理器)接口的authenticate方法完全一样。
|
|
providers 属性 定义了 提供者管理器的集合,ProviderManager(提供者管理器)逐一遍历这个认证提供者的集合并调用提供者的authenticate方法 ,如果一个提供者认证失败会尝试另外一个提供者直到某一个认证提供者能够成功的验证该用户的身份, 以保证获取不同来源的身份认证。下面表格列出了系统提供的一些认证提供者:
提 供 者
|
作 用
|
DaoAuthenticationProvider
|
从数据库中读取用户信息验证身份
|
AnonymousAuthenticationProvider
|
匿名用户身份认证
|
RememberMeAuthenticationProvider
|
已存 cookie中的用户信息身份认证
|
AuthByAdapterProvider
|
使用容器的适配器验证身份
|
CasAuthenticationProvider
|
根据 Yale中心认证服务验证身份 , 用于实现单点登陆
|
JaasAuthenticationProvider
|
从 JASS登陆配置中获取用户信息验证身份
|
RemoteAuthenticationProvider
|
根据远程服务验证用户身份
|
RunAsImplAuthenticationProvider
|
对身份已被管理器替换的用户进行验证
|
X509AuthenticationProvider
|
从 X509认证中获取用户信息验证身份
|
TestingAuthenticationProvider
|
单元测试时使用
|
从上面的表中可以看出,系统为我们提供了不同的认证提供者, 每个认证提供者会对自己指定的证明信息进行认证,如 DaoAuthenticationProvider 仅对UsernamePasswordAuthenticationToken 这个证明信息进行认证。
在实际项目中,用户的身份和权限信息可能存储在不同的安全系统中(如数据库 ,LDAP服务器 ,CA 中心)。
作为程序员,我们可以根据需要选择不同的AuthenticationProvider(认证提供者) 来对自己的系统提供认证服务。
这里我们着重介绍 DaoAuthenticationProvider,它从数据库中读取用户信息验证身份,配置如下:
<!---->1 < bean id ="daoAuthenticationProvider"
class ="org.springframework.security.providers.dao.DaoAuthenticationProvider"
2 p:passwordEncoder-ref ="passwordEncoder"
3 p:userDetailsService-ref ="userDetailsService" />
4 < bean id ="passwordEncoder"
5 class ="org.springframework.security.providers.encoding.Md5PasswordEncoder" />
还记得前面配置的 RememberMeServices 吗?它也有一个和 DaoAuthenticationProvider同样的属性 userDetailsService ,这是系统提供的一个接口(org.springframework.security.userdetails. UserDetailsService ),在这里我们把它单独提出来进行介绍。
首先我们需要了解Spring Security为我们提供的另外一个重要的组件,org.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 ,从而可以获取用户名,密码以及权限等信息。代码如下:
<!---->1 UserDetails details = (UserDetails)authentication.getPrincipal();
2
3 GrantedAuthority[] authority = details.getAuthorities();
前面介绍了 DaoAuthenticationProvider,它可以从数据库中读取用户信息,同样也可以从一个用户属性文件中读取,下一篇文章中我们在介绍如何从数据库中读取用户信息,当然还会涉及到更深入的东西,比如根据自己系统的需要自定义 UserDetails 和UserDetailsService,这个只是让你对整个系统有个简单的了解,所以我们使用 用户属性文件 (users.properties )来存储用户信息:
<!---->1 admin = admin,ROLE_SUPERVISOR
2
3 user1 = user1,ROLE_USER
4
5 user2 = user2,ROLE_USER
6
7 user3 = user3,disabled,ROLE_USER
配置 userDetailsService :
<!---->1 < bean id ="userDetailsService"
2
3 class ="org.springframework.security.userdetails.memory.InMemoryDaoImpl" >
4 < property name ="userProperties" >
5 < bean class ="org.springframework.beans.factory.config.PropertiesFactoryBean"
6 p:location ="/WEB-INF/users.properties" />
7 </ property >
8 </ bean >
InMemoryDaoImpl 类是 UserDetailsService 接口的一个实现,它从属性文件里读取用户信息,Spring Security使用一个属性编辑器将用户信息为我们组织成一个org.springframework.security.userdetails.memory. UserMap 类的对象,我们也可以直接为它提供一个用户权限信息的列表,详见applicationContext-security.xml配置文件。
UserMap 字符串的每一行都用键值对的形式表示,前面是用户名,然后是等号,后面是赋予该用户的密码/权限等信息,它们使用逗号隔开。比如:
<!---->1 admin = admin,ROLE_SUPERVISOR
定义了一个名为 admin 的用户登录密码为 admin ,该用户拥有 ROLE_SUPERVISOR 权限,再如 users.properties文件中配置的 名为 user3 的用户登录密码为 user3 ,该用户拥有 ROLE_USER 权限,disabled定义该用户不可用,为被激活( UserDetails 的 isEnabled 方法)。
即使是系统的开发者或者说是最终用户,都不应该看到系统中有明文的密码。所以,Spring Security考虑的还是很周到的,为我们提供的密码加密的功能。正如你在Dao认证提供者( DaoAuthenticationProvider)中看到的,passwordEncoder 属性配置的就是一个密码加密程序(密码编码器 )。这里我们使用MD5加密,可以看
配置文件中的scott用户,你还能看出他的密码是什么吗?当然这里只是演示功能,其它用户还是没有改变,你可以自己试试。系统为我们提供了一些常用的密码编码器(这些编码器都位于org.springframework.secu rity.providers.encoding包 下):
PlaintextPasswordEncoder (默认) ——不对密码进行编码,直接返回未经改变的密码;
Md4PasswordEncoder —— 对密码进行消息摘要(MD4)编码;
Md5PasswordEncoder —— 对密码进行消息摘要(MD5)编码;
ShaPasswordEncoder —— 对密码进行安全哈希算法(SHA)编码。
你可以根据需要选择合适的密码编码器,你也可以 设 置 编码 器的 种 子源 (salt source) 。一个 种 子源 为编码 提供 种 子 (salt),或者称 编码 的密 钥,这里不再赘述。
这里附加介绍了不少东西,希望你还没有忘记在 AuthenticationManager( 认证管理器)中还配置了一个名为sessionController 的Bean,这个Bean可以阻止用户在进行了一次成功登录以后在进行一次成功的登录。在 applicationContext-security.xml 配置文件添加 sessionController 的配置:
<!---->1 < bean id ="concurrentSessionController"
2
3 class ="org.springframework.security.concurrent.ConcurrentSessionControllerImpl"
4 p:maximumSessions ="1"
5 p:exceptionIfMaximumExceeded ="true"
6 p:sessionRegistry-ref ="sessionRegistry" />
7 < bean id ="sessionRegistry"
8
9 class ="org.springframework.security.concurrent.SessionRegistryImpl" />
maximumSessions 属性配置了只允许同一个用户登录系统一次,exceptionIfMaximumExceeded 属性配置了在进行第二次登录是是否让第一次登录失效。这里设置为true不允许第二次登录。要让此功能生效,我们还需要在web.xml文件中添加一个监听器,以让Spring Security能获取Session的生命周期事件,配置如下:
<!---->1 < listener >
2 < listener-class >
3 org.springframework.security.ui.session.HttpSessionEventPublisher
4 </ listener-class >
5 </ listener >
HttpSessionEventPublisher 类实现javax.servlet.http.HttpSessionListener 接口,在Session被创建的时候通过调用ApplicationContext 的publishEvent(ApplicationEvent event) 发布HttpSessionCreatedEvent 类型的事件,HttpSessionCreatedEvent 类继承自org.springframework.context.ApplicationEvent 类的子类 HttpSessionApplicationEvent 抽象类。
concurrentSessionController 使用sessionRegistry 来完成对发布的Session的生命周期事件 的处理,org.springframework.security.concurrent. SessionRegistryImpl (实现了SessionRegistry接口), SessionRegistryImpl类还实现了Spring Framework 的事件监听org.springframework.context.Application Listener接口,并实现了该接口定义的onApplicationEvent(ApplicationEvent event) 方法用于处理Applic ationEvent类型的事件,如果你了解Spring Framework的事件处理,那么这里你应该可以很好的理解。
认证管理器到此介绍完毕了,认证过程过滤器也介绍完了,接下来我们继续介绍过滤器链的下一个过滤器
securityContextHolderAwareRequestFilter :
<!---->1 < bean id ="securityContextHolderAwareRequestFilter"
2 class ="org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter" />
这个过滤器使用 装饰模式 (Decorate Model ),装饰的HttpServletRequest对象。其Wapper是ServletRequest包装类HttpServletRequestWrapper的子类(如SavedRequestAwareWrapper或SecurityContextHolderAwareRequestWrapper),附上获取用户权限信息,request参数,headers 和 cookies 的方法。
rememberMeProcessingFilter 过滤器配置:
< bean id = "rememberMeProcessingFilter"
class = "org.springframework.security.ui.rememberme.RememberMeProcessingFilter"
p:authenticationManager-ref = "authenticationManager"
p:rememberMeServices-ref = "rememberMeServices" />
当SecurityContextHolder中不存在Authentication用户授权信息时,rememberMeProcessingFilter就会调用rememberMeServices 的autoLogin() 方法从cookie中获取用户信息自动登录。
anonymousProcessingFilter 过滤器配置:
<!---->1 < bean id ="anonymousProcessingFilter"
2 class ="org.springframework.security.providers.anonymous.AnonymousProcessingFilter"
3 p:key ="springsecurity"
4 p:userAttribute ="anonymousUser,ROLE_ANONYMOUS" />
如果不存在任何授权信息时,自动添加匿名用户身份至SecurityContextHolder中,就是这里配置的userAttribute,系统为用户分配一个ROLE_ANONYMOUS权限。
exceptionTranslationFilter (异常处理过滤器) ,该过滤器用来处理在系统认证授权过程中抛出的异常,主要是 处理 AccessDeniedException 和AuthenticationException 两个异常并根据配置跳转到不同URL:
<!---->1 < bean id ="exceptionTranslationFilter"
2 class ="org.springframework.security.ui.ExceptionTranslationFilter"
3 p:accessDeniedHandler-ref ="accessDeniedHandler"
4 p:authenticationEntryPoint-ref ="authenticationEntryPoint" />
5 <!-- 处理AccessDeniedException -->
6 < bean id ="accessDeniedHandler"
7 class ="org.springframework.security.ui.AccessDeniedHandlerImpl"
8 p:errorPage ="/accessDenied.jsp" />
9 < bean id ="authenticationEntryPoint"
10 class ="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint"
11 p:loginFormUrl ="/login.jsp"
12 p:forceHttps ="false" />
accessDeniedHandler 用于处理AccessDeniedException异常,当用户没有权限访问当前请求的资源时抛出此异常,并跳转自这里配置的/accessDenied.jsp页面。
authenticationEntryPoint (认证入口点) ,这里定义了用户登录的页面。系统为我们提供了3个认证入口点的实现:
认 证 入 口 点
|
作 用
|
BasicProcessingFilterEntryPoint
|
通过向浏览器发送一个HTTP 401(未授权)消息,由浏览器弹出登录对话框,提示用户登录
|
AuthenticationProcessingFilterEntryPoint
|
将用户重定向到一个基于HTML表单的登录页面
|
CasProcessingFilterEntryPoint
|
将用户重定向至一个Yale CAS登录页面
|
这里我们使用AuthenticationProcessingFilterEntryPoint 认证入口点,提供给用户一个友好的登录界面,只是为了给用户更好的体验。
filterSecurityInterceptor (过滤器安全拦截器) ,该过滤器首先调用认证管理器来判断用户是否已被成功验证,如果没有被验证则重定向到登录界面。否则,从Authentication获取用户的权限信息,然后从objectDefinitionSource中获取URL所对应的权限,最后调用accessDecisionManager(访问决策管理器)来判断用户当前拥有的权限是否与当前受保护的URL资源对应的权限匹配,如果匹配就可以访问该URL资源, 否则将抛出 AccessDeniedException 异常 并 返回客户端浏览器一个403错误(如果用户定义了accessDenied页面则会被重定向到该页,见:异常处理过滤器exceptionTranslationFilter中配置的accessDeniedHandler Bean),访问决策管理的的工作机制将在随后更详细介绍,这里先给出过滤器安全拦截器的配置如下:
<!----> 1 < bean id ="filterSecurityInterceptor"
2
3 class ="org.springframework.security.intercept.web.FilterSecurityInterceptor"
4
5 p:authenticationManager-ref ="authenticationManager"
6
7 p:accessDecisionManager-ref ="accessDecisionManager" >
8 < property name ="objectDefinitionSource" >
9 < value > <![CDATA[
10
11 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
12 PATTERN_TYPE_APACHE_ANT
13 /admins/**=ROLE_SUPERVISOR
14 /user/**=ROLE_USER,IS_AUTHENTICATED_REMEMBERED
15 /default.jsp=ROLE_USER,IS_AUTHENTICATED_REMEMBERED
16 /**=IS_AUTHENTICATED_ANONYMOUSLY
17 ]]> </ value >
18 </ property >
19 </ bean >
从配置可以看出来,过滤器安全拦截器用到了我们前面配置的认证管理器,过滤器安全拦截器使用authenticationManager并调用它的providers(提供者列表)来对用户的身份进行验证并获取用户拥有的权限。如果用户被成功认证,过滤器安全拦截器将会使用accessDecisionManager (访问决策管理器)来判断已认证的用户是否有权限访问受保护的资源,这些受保护的资源由objectDefinitionSource属性定义。
访问决策管理器(accessDecisionManager) :
<!----> 1 < bean id ="accessDecisionManager"
2 class ="org.springframework.security.vote.AffirmativeBased"
3 p:allowIfAllAbstainDecisions ="false" >
4 < property name ="decisionVoters" >
5 < list >
6 < bean class ="org.springframework.security.vote.RoleVoter" />
7 < bean class ="org.springframework.security.vote.AuthenticatedVoter" />
8 </ list >
9 </ property >
10 </ bean >
身份验证只是Spring Security安全机制的第一步,访问决策管理器验证用户是否有权限访问相应的资源(filterSecurityInterceptor中objectDefinitionSource 属性定义的访问URL需要的属性信息)。
org.springframework.security. AccessDecisionManager 接口定义了用于验证用户是否有权限访问受保护资源的decide方法,另一个supports方法根据受保护资源的配置属性(即访问这些资源所需的权限)来判断该访问决策管理器是否能做出针对该资源的访问决策。decide方法最终决定用户有无访问权限, 如果没有则抛出 AccessDeniedException 异常(面前也提到过,你应该在回过头去看看)。
分享到:
相关推荐
"springsecurity-namespace"可能指的是Spring Security的XML命名空间配置。在Spring Security的早期版本中,使用XML配置是最常见的实践。例如,你可能会看到以下片段: ```xml **" access="hasRole('ROLE_ADMIN')...
在“Spring Security学习总结2_2”中,我们可能涉及了对Spring Security更深入的探讨,特别是关于其核心概念和实际应用的细节。 首先,Spring Security的核心组件包括Security Context(安全上下文)、...
### Spring Security 学习总结与应用实践 #### 引言 在深入了解Spring Security之前,我们需要认识到,传统的权限验证逻辑往往杂糅于业务逻辑之中,这种混合不仅使得代码难以维护,而且降低了系统的整体效率。每当...
1. **Filter Security Interceptor**:这是SpringSecurity的主要过滤器,负责检查请求并决定是否允许访问。它会根据预定义的访问控制规则进行判断。 2. **Authentication Manager**:处理用户认证的组件,可以使用...
【Spring Security 学习总结】 Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于保护基于 Java 的应用程序。本学习总结文档主要针对初学者,旨在剖析一个不安全的应用程序并阐述如何通过 ...
在"Spring Security学习总结一(补命名空间配置)"的文件中,可能涵盖了如何在Spring Security的XML配置中补充命名空间的步骤。命名空间的引入是为了简化配置,例如`<http>`元素用于配置安全拦截和访问规则,`...
SpringSecurity学习总结一.pdf
总结来说,"REST-spring-security"项目展示了如何使用Spring Security来保护RESTful Web服务,包括身份验证、授权、访问控制和安全配置。这个项目可以帮助开发者理解如何在实际应用中实现安全的REST API,确保服务的...
### Spring Security 学习总结 #### 一、Spring Security 概述 Spring Security 是一个功能强大的安全框架,它为基于 Java 的应用程序提供了认证(authentication)和授权(authorization)功能。在 Spring ...
《Spring Security 3.1 学习指南及资源解析》 Spring Security是Java平台上的一款强大且高度可定制的安全框架,广泛应用于企业级Web应用的安全管理。本篇文章将围绕"Spring Security 3.1"这一主题,深入探讨其核心...
### Spring Security 概述与应用实践 #### 一、引言 在当今互联网时代,网络安全问题日益凸显,尤其是Web应用程序的...同时,结合实际案例的学习,能够帮助我们更好地理解和掌握Spring Security的核心概念与使用技巧。
总结,Spring Security 3的源码分析是一个深度学习的过程,涵盖了安全领域的多个方面。通过理解其内部工作机制,开发者可以更好地利用这一强大的框架,为应用程序提供安全的保障。同时,源码分析也能帮助开发者解决...
对于初学者,建议从官方文档或教程开始学习,逐步熟悉Spring Security的安装、配置和使用流程。 #### Security命名空间配置 Spring Security通过XML命名空间简化了安全相关的配置。这部分文档详细介绍了如何使用...
spring security 学习总结暑假的时候在学习了Spring安全并成功运用到了项目中。在实践中摸索出了一套结合JSON +智威汤逊(JSON网络令牌)+Spring引导+ Spring Security的技术的权限方案趁着国庆假期记录一下。 内容 ...
### Spring Security3中文教程知识点概览 #### 一、安全核心概念与起步 Spring Security是Spring框架中的一个重要组成部分,主要用于为Web应用提供安全防护。它不仅提供了强大的认证和授权功能,还支持各种加密...
总结起来,"springSecurityTest.zip"文件提供了一个完整的环境,让你可以动手实践Spring Security的基础用法。通过学习其中的代码、笔记和文档,你将理解Spring Security如何与Spring框架协同工作,如何设置认证和...