- 浏览: 305995 次
文章分类
最新评论
-
流年末年:
那四个参数还是没看懂.....能不能解释下showPassst ...
我写的密码强度验证方法(原创) -
kingcs2008:
// 验证pws.jsshowPassstrength(&qu ...
我写的密码强度验证方法(原创) -
h957355152:
请问博主这个怎么用呢?我直接放到jsp里面调用showPass ...
我写的密码强度验证方法(原创) -
qq_15138059:
我写的全国省市县三级联动菜单,拿出来和大家分享了(原创) -
valenon:
评论呢?从MAIL FROM命令开始貌似就出错了:500 Er ...
如何发送伪造的电子邮件
实现自定义的 AuthenticationProvider
在很多场景下,你的应用需要跳出 Spring Security 功能的边界,可能会需要实现自己的 AuthenticationProvider 。回忆在第二章中 AuthenticationProvider 的角色,在整个认证过程中,它接受安全实体请求提供的凭证(即 Authentication 对象或 authentication token )并校验其正确性和合法性。
通过AuthenticationProvider 实现一个简单的单点登录
通常,应用允许以用户或客户端方式登录。但是,有一种场景也很常见,尤其是在广泛使用的应用中,即允许系统中的不同用户以多种方式登录。
假设我们的系统与一个简单的“单点登录”提供者进行集成,用户名和密码分别在 HTTP 头中的 j_username 和 j_password 发送。除此以外, j_signature 头信息包含了用户名和密码的随意编码算法形成的字符串,以辅助安全请求。
【不要使用这个例子作为真实单点登录的解决方案。这个例子很牵强,只是为了说明实现一个完全自定义 AuthenticationProvider 的步骤。真正的 SSO 解决方案显然会更安全并涉及到几次的握手以建立可信任的凭证。 Spring Security 支持几种 SSO 解决方案,包括中心认证服务( CAS )和 SiteMinder ,我们将会在第十章:使用中心认证服务实现单点登录中介绍。实际上, Spring Security 提供了一个类似的过滤器用来进行 SiteMinder 请求头的认证,即 o.s.s.web.authentication.preauth.RequestHeaderAuthenticationFilter ,也是这种类型功能的一个好例子。】
对于 admin 用户的登录,我们的算法期望在请求头中包含如下的数据:
请求头 |
值 |
j_username |
admin |
j_password |
admin |
j_signature |
admin|+|admin |
一般来讲, AuthenticationProvider 将会寻找特定的 AuthenticationToken ,而后者会在过滤器链中位置比较靠前的 servlet filter 里面进行填充赋值(明确会在 AuthenticationManager 访问检查执行之前),如下图描述:
在这种方式中, AuthenticationToken 的提供者与其消费者 AuthenticationProvider 有一点脱离关系了。所以,在实现自定义 AuthenticationProvider 时,通常还需要实现一个自定义的 servlet 过滤器,其作用是提供特定的 AuthenticationToken 。
自定义认证 token
我们实现自定义的方法会尽可能的使用 Spring Security 的基本功能。基于此,我们会扩展并增强基本类如 UsernamePasswordAuthenticationToken ,并添加一个新的域来存储我们已编码的签名字符串。最终的类 com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationToken ,如下:
- package com.packtpub.springsecurity.security;
- // imports omitted
- public class SignedUsernamePasswordAuthenticationToken
- extends UsernamePasswordAuthenticationToken {
- private String requestSignature;
- private static final long serialVersionUID =
- 3145548673810647886L;
- /**
- * Construct a new token instance with the given principal,
- credentials, and signature.
- *
- * @param principal the principal to use
- * @param credentials the credentials to use
- * @param signature the signature to use
- */
- public SignedUsernamePasswordAuthenticationToken(String principal,
- String credentials, String signature) {
- super (principal, credentials);
- this .requestSignature = signature;
- }
- public void setRequestSignature(String requestSignature) {
- this .requestSignature = requestSignature;
- }
- public String getRequestSignature() {
- return requestSignature;
- }
- }
我们可以看到 SignedUsernamePasswordAuthenticationToken 是一个简单的 POJO 类,扩展自 UsernamePasswordAuthenticationToken 。 Tokens 并不需要太复杂——它们的主要目的就是为后面的校验封装凭证信息。
实现对请求头处理的 servlet 过滤器
现在,我们要写 servlet 过滤器的代码,它负责将请求头转换成我们新定义的 token 。同样的,我们扩展对应的 Spring Security 基本类。在本例中, o.s.s.web.authentication.
AbstractAuthenticationProcessingFilter 满足我们的要求。
【基本过滤器 AbstractAuthenticationProcessingFilter 在 Spring Security 中是很多进行认证过滤器的父类(包括 OpenID 、中心认证服务以及基于 form 的用户名和密码登录)。这个类提供了标准的认证逻辑并适当织入了其它重要的资源如 RememberMeServices 和 ApplicationEventPublisher (本章的后面将会讲解到)。】
现在,让我们看一下代码:
- // imports omitted
- public class RequestHeaderProcessingFilter extends
- AbstractAuthenticationProcessingFilter {
- private String usernameHeader = "j_username" ;
- private String passwordHeader = "j_password" ;
- private String signatureHeader = "j_signature" ;
- protected RequestHeaderProcessingFilter() {
- super ( "/j_spring_security_filter" );
- }
- @Override
- public Authentication attemptAuthentication
- (HttpServletRequest request,HttpServletResponse response)
- throws AuthenticationException,
- IOException, ServletException {
- String username = request.getHeader(usernameHeader);
- String password = request.getHeader(passwordHeader);
- String signature = request.getHeader(signatureHeader);
- SignedUsernamePasswordAuthenticationToken authRequest =
- new SignedUsernamePasswordAuthenticationToken
- (username, password, signature);
- return this .getAuthenticationManager().authenticate(authRequest);
- }
- // getters and setters omitted below
- }
可以看到,这个比较简单的过滤器查找三个已命名的请求头,正如我们已经规划的那样(如果需要的话,可以通过 bean 属性进行配置),并监听默认的 URL /j_spring_security_filter 。正如其它的 Spring Security 过滤器那样,这是一个虚拟的 URL 并被我们的过滤器的基类 AbstractAuthenticationProcessingFilter 所识别,基于此这个过滤器采取行动尝试创建 Authentication token 并认证用户的请求。
【区分参与认证 token 流程的各个组件。在这个功能中,很容易被这些术语、接口和类的名字搞晕。代表要认证的 token 接口是 o.s.s.core.Authentication ,这个接口的实现将以后缀 AuthenticationToken 结尾。这是一个很简单的方式来区分 Spring Security 提供的认证实现类。】
在本例中,我们尽可能将错误检查最小化(译者注:即参数的合法性与完整性的检查)。可能在实际的应用中,会校验是否所有头信息都提供了以及在发现用户提供信息不正确的时候要抛出异常或对用户进行重定向。
一个细小的配置变化是需要将我们的过滤器插入到过滤器链中:
- < http auto-config = "true" ... >
- < custom-filter ref = "requestHeaderFilter"
- before = "FORM_LOGIN_FILTER" />
- </ http >
你可以看到过滤器代码最后请求 AuthenticationManager 来进行认证。这将最终委托配置的 AuthenticationProvider ,它们中的一个要支持检查 SignedUsernamePasswordAuthenticationToken 。接下来,我们需要书写一个 AuthenticationProvider 来做这件事情。
实现基于请求头的 AuthenticationProvider
现在,我们写一个 AuthenticationProvider 的实现类,即 com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationProvider ,负责校验我们自定义 Authentication token 的签名。
- package com.packtpub.springsecurity.security;
- // imports omitted
- public class SignedUsernamePasswordAuthenticationProvider
- extends DaoAuthenticationProvider {
- @Override
- public boolean supports(Class<? extends Object> authentication) {
- return (SignedUsernamePasswordAuthenticationToken . class .isAssignableFrom(authentication));
- }
- @Override
- protected void additionalAuthenticationChecks
- (UserDetails userDetails,
- UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- super .additionalAuthenticationChecks
- (userDetails, authentication);
- SignedUsernamePasswordAuthenticationToken signedToken =
- (SignedUsernamePasswordAuthenticationToken) authentication;
- if (signedToken.getRequestSignature() == null ) {
- throw new BadCredentialsException(messages.getMessage(
- "SignedUsernamePasswordAuthenticationProvider
- .missingSignature", " Missing request signature"),
- isIncludeDetailsObject() ? userDetails : null );
- }
- // calculate expected signature
- if (!signedToken.getRequestSignature()
- .equals(calculateExpectedSignature(signedToken))) {
- throw new BadCredentialsException(messages.getMessage
- ("SignedUsernamePasswordAuthenticationProvider
- .badSignature", " Invalid request signature"),
- isIncludeDetailsObject() ? userDetails : null );
- }
- }
- private String calculateExpectedSignature
- (SignedUsernamePasswordAuthenticationToken signedToken) {
- return signedToken.getPrincipal() + "|+|" +
- signedToken.getCredentials();
- }
- }
你可以看到我们再次扩展了框架中的类 DaoAuthenticationProvider ,因为有用的数据访问代码仍然需要进行实际的用户密码校验以及通过 UserDetailsService 加载 UserDetails 。
这个类有些复杂,所以我们将分别介绍其中的每个方法。
Supports 方法,是重写父类的方法,向 AuthenticationManager 指明当前 AuthenticationProvider 要进行校验的期望运行时 Authentication token 。
接下来, additionalAuthenticationChecks 方法被父类调用,此方法允许子类对 token 进行特有的校验。这正适合我们的策略,所以添加上我们对 token 新的签名检查。基本上已经完成了我们自定义“简单 SSO ”的实现,仅剩一处配置了。
连接AuthenticationProvider
一个常见的要求就是将一个或更多的 AuthenticationProvider 接口连接起来,因为用户可能会以几种校验方式中的某一种登录系统。
因为到目前为止,我们还没有了解其它的 AuthenticationProvider ,我们可以假设以下的需求,即使用标准的用户名和密码基于 form 的认证以及前面实现的自定义简单 SSO 认证。当配置了多个 AuthenticationProvider 时,每个 AuthenticationProvider 都会检查过滤器提供给它的 AuthenticationToken ,仅当这个 token 类型它支持时才会处理这个 token 。以这种方式,你的应用同时支持不同的认证方式并不会有什么坏处。
连接多个 AuthenticationProvider 实际上很简单。只需要在我们的 dogstore-security.xml 配置文件中声明另一个 authentication-provider 引用。
- < authentication-manager alias = "authenticationManager" >
- < authentication-provider ref = "signedRequestAuthenticationProvider" />
- < authentication-provider user-service-ref = "jdbcUserService" >
- < password-encoder ref = "passwordEncoder" >
- < salt-source ref = "saltSource" />
- </ password-encoder >
- </ authentication-provider >
- </ authentication-manager >
与我们安全配置文件中引用的其它 Spring bean 一样, signedRequestAuthenticationProvider 引用就是我们的 AuthenticationProvider ,它将在 dogstore-base.xml 中与其它的 Spring bean 一起进行配置。
- < bean id = "signedRequestAuthenticationProvider" class ="com.packtpub.springsecurity.security
- .SignedUsernamePasswordAuthenticationProvider">
- < property name = "passwordEncoder" ref = "passwordEncoder" />
- < property name = "saltSource" ref = "saltSource" />
- < property name = "userDetailsService" ref = "jdbcUserService" />
- </ bean >
我们自定义的 AuthenticationProvider 的 bean 属性其实都是父类所需要的。这些也都指向了我们在 AuthenticationManager 的中第二个 authentication-provider 声明中的那些 bean 。
最终已经完成了支持这个简单单点登录功能的编码和配置,至此可以给自己一个小小的喝彩。但是,还有一个小问题——我们应该怎样操作请求的 http 头以模拟我们的 SSO 认证提供者呢?
使用请求头模拟单点登录
尽管我们的场景比较牵强,但是有一些商业和开源的单点登录解决方案,它们能够被配置以通过 HTTP 请求头发送凭证信息,最具有代表性的是 CA (以前的 Netegrity ) SiteMinder 。
【需要特别注意的是,与 SSO 方案集成的应用是不能通过用户的直接请求访问的。通常情况下, SSO provider 功能作为代理,通过它确定用户的请求流程(是安全的)或 provider 持有关于密码的信息并将这些信息与单个的安全应用隔离。在没有完全了解一个其使用的硬件、网络和安全设施之前,不要部署 SSO 应用。】
Mozilla Firefox 的浏览器扩展,名为 Modify Headers (可以在以下地址获得: http://modifyheaders.mozdev.org ),是一个很简单的工具能够用来模拟伪造 HTTP 头的请求。以下的截图表明了如何使用这个工具添加我们的 SSO 方案所希望得到的请求头信息:
将所有的头信息标示为
Enabled
,访问这个
URL
:
http://localhost:8080/JBCPPets/j_spring_security_filter
,会发现我们能够自动登录系统。你可能也会发现我们给予
form
的登录还能继续可用,这是因为保留了这两个
AuthenticationProvider
实现以及过滤器链中对应的过滤器。
(译者注:说实话,作者这个实现自定义 AuthenticationProvider 的例子真的是比较牵强,但是还算完整描述出了其实现方式,想深入了解 AuthenticationProvider 自定义的朋友,可以参照 Spring Security 提供的 CasAuthenticationProvider 等实现。)
实现自定义AuthenticationProviders 时要考虑的事项
尽管我们刚刚看到的例子并没有阐述你想构建的 AuthenticationProvider ,但是任何自定义 AuthenticationProvider 的步骤是类似的。这个练习的关键在于:
l 基于用户的请求完成一个 Authentication 实现的任务一般情况下会在过滤器链中的某一个中进行。取决于是否校验凭证的数据,这个校验组件可能要进行扩展;
l 基于一个合法的 Authentication 认证用户的任务需要 AuthenticationProvider 的实现来完成。请查看我们在第二章中讨论过的 AuthenticationProvider 所被期望拥有的功能;
l 在一些特殊的场景下,如果未认证的 session 被发现,可能会需要自定义的 AuthenticationEntryPoint 。我们将会在本章接下来的部分更多了解这个接口,也会在第十章介绍中心认证服务( CAS )时,介绍一些 AuthenticationEntryPoint 的实际例子。
如果你能时刻记住它们的角色,当你在开发应用特定的 AuthenticationProvider 时,会在实现和调试过程中少很多的迷惑。
发表评论
-
spring-security3 配置和使用(二)承上
2011-12-22 06:42 10632、xml配置,配置内容如下: Xml代码 ... -
spring-security3 配置和使用 (一)(转载)
2011-12-22 06:43 955最近项目中要使用到spring-security,可能研究 ... -
SpringSecurity3.X--一个简单实现(转载)
2011-12-22 06:43 2675作者对springsecurity研究不深,算是个初学者吧,最 ... -
SpringSecurity3.X--验证码(转载)
2011-12-22 06:44 1069一般来说,登录时都会要求用户输入验证码,以防止恶意登录。 可 ... -
SpringSecurity3.X--前台与后台登录认证(转载)
2011-12-23 06:33 3460不过一般我们在管理系统时都会分前台与后台,也就是说,前台与后台 ... -
SpringSecurity3.X--remember-me(转载)
2011-12-22 06:44 1748笔者在SpringSecurity中配置remember-me ... -
《Spring Security3》第六章第七部分翻译(认证事件处理与小结)
2011-12-23 06:34 1344认证事件处理 ... -
《Spring Security3》第六章第六部分翻译(Spring Security基于bean的高级配置)
2011-12-23 06:34 1056Spring Security 基于bean 的高级配 ... -
《Spring Security3》第六章第五部分翻译(手动配置Spring Security设施的bean)(转载)
2011-12-23 06:34 1028手动配置Spring Security 设施的be ... -
《Spring Security3》第六章第四部分翻译(异常处理)(转载)
2011-12-23 06:34 1247理解和配置异常处理 ... -
《Spring Security3》第六章第三部分翻译(Session的管理和并发)(转载)
2011-12-24 10:20 4230Session 的管理和并发 ... -
《Spring Security3》第六章第一部分翻译(自定义安全过滤器)(转载)
2011-12-24 10:21 1126第六章 高级配置和扩展 到目前为止,我 ... -
《Spring Security3》第五章第四部分翻译(方法安全的高级知识和小结)(转载)
2011-12-24 10:22 1060方法安全的高级知 ... -
《Spring Security3》第五章第三部分翻译(保护业务层)
2011-12-24 10:22 892保护业务层 到目前为止,在 ... -
《Spring Security3》第五章第二部分翻译下(实现授权精确控制的方法——页面级权限)(转载)
2011-12-25 00:47 1028使用控制器逻辑进行有条件渲染内容 ... -
《Spring Security3》第五章第二部分翻译上(实现授权精确控制的方法——页面级权限)(转载)
2011-12-25 00:47 975实现授权精确控制的方法 精确的授权指的是基于用 ... -
《Spring Security3》第五章第一部分翻译(重新思考应用功能和安全) (转载)
2011-12-25 00:47 951第五章 精确的 ... -
《Spring Security3》第四章第四部分翻译(Remember me后台存储和SSL)(转载)
2011-12-25 00:47 1267将 Remember me 功能 ... -
《Spring Security3》第四章第三部分翻译下(密码加salt)(转载)
2011-12-25 00:48 1813你是否愿意在密码上添加点salt ? 如果安 ... -
《Spring Security3》第四章第三部分翻译上(配置安全的密码)(转载)
2011-12-26 00:41 1031配置安全的密码 我们 ...
相关推荐
### 第二章:深入理解Spring Security3 本章深入探讨了Spring Security3的内部机制,包括安全过滤器链、认证管理器(Authentication Manager)的工作原理以及如何定制这些组件以满足特定需求。 ### 第三章:高级安全...
在"springsecurity学习笔记"中,你可能会涉及以下主题: - Spring Security的基本配置,包括web安全配置和全局安全配置。 - 如何自定义认证和授权流程,比如实现自定义的AuthenticationProvider和...
9. **自定义**:Spring Security非常灵活,允许开发者根据需求自定义大部分组件,如访问决策管理器、权限评估器等,以满足特定业务场景。 10. **与其他Spring框架的集成**:Spring Security与Spring Boot、Spring ...
2. **集成过程**:在SpringMVC项目中集成SpringSecurity,首先需要在pom.xml文件中引入相应的依赖,接着配置SpringSecurity的XML配置文件,定义安全规则、用户认证方式等。 3. **默认账户和密码**:“admin,admin...
Spring Security 是一个强大的和高度可定制的身份验证和...总的来说,Spring Security 3.x第五章的实例将帮助开发者深入理解这个框架的使用,通过具体的代码示例来实践安全性配置,从而更好地保护他们的Spring应用。
在SpringSecurity的配置中,会定义一个自定义的AuthenticationProvider来处理用户的登录认证,以及UserDetailsService来获取用户信息。此外,还需要配置HttpSecurity以拦截特定URL,根据用户的角色和权限决定是否...
6. **CSRF防护(Cross-Site Request Forgery)**:SpringSecurity提供了内置的CSRF防护,通过生成和验证CSRF令牌,防止恶意第三方发起未经授权的操作。 7. **密码加密**:SpringSecurity支持多种密码加密策略,包括...
- **自定义AuthenticationProvider**:如果需要使用非默认的验证逻辑,可以创建自己的AuthenticationProvider。 - **自定义UserDetailsService**:处理用户详情,从数据库或其他来源加载用户信息。 6. **异常处理...
本离线手册是SpringSecurity 3版本的详细指南,对于开发者来说,是一份非常宝贵的参考资料。 在SpringSecurity 3中,主要包含了以下几个核心概念: 1. **认证(Authentication)**:这是验证用户身份的过程。...
用户可以通过自定义AuthenticationProvider实现自己的认证逻辑,确保用户身份的正确性。 - **授权**:Spring Security的访问决策管理器(Access Decision Manager)支持基于角色、基于权限和自定义策略的授权。Role-...
例如,可以使用OAuth2 实现第三方登录,Spring Security 处理内部认证和授权。 2. **授权服务器**:Spring Security 提供OAuth2 提供者支持,可以搭建自己的授权服务器,实现令牌的颁发和验证。 3. **保护API**:在...
8. **OAuth2集成**:Spring Security还支持OAuth2协议,允许第三方应用获取有限的访问权限到受保护的资源,增强了现代Web应用的安全性和灵活性。 在“SpringSecurityDemo”这个示例项目中,你可能会看到如何配置...
- Spring Security 3支持OAuth2协议,可以用于实现第三方登录功能,如Google、Facebook登录。 8. **AOP集成** - Spring Security利用Spring的AOP(面向切面编程)实现方法级别的安全控制,可以对方法调用进行访问...
- **OAuth2集成**: 如何使用Spring Security与OAuth2结合,实现第三方登录功能。 - **CORS支持**: 设置跨域请求的安全策略,允许不同源的Web应用进行交互。 - **国际化的错误处理**: 如何定制Spring Security的...
6. **SpringSecurity的包结构**:在提供的"ss3"压缩包中,可能包含了SpringSecurity的相关库文件,如spring-security-config、spring-security-core、spring-security-web等。这些库提供了实现上述功能所需的所有类...
第二部分 架构与实现 73 9.技术概述 73 9.1运行环境 73 9.2核心组件 74 9.2.1 SecurityContextHolder,SecurityContext和认证对象 74 获取有关当前用户的信息 75 9.2.2 UserDetailsService 75 9.2.3授予权力 77 ...
10. **OAuth2集成**:SpringSecurity可以与OAuth2框架集成,实现第三方登录、API保护等功能。 通过理解以上核心概念,开发者能够更好地利用SpringSecurity为应用程序构建稳固的安全防护。在实践中,根据项目需求...
6. **OAuth支持**:虽然3.1版本的OAuth支持可能相对有限,但Spring Security已经开始提供对OAuth协议的基础支持,允许应用与其他OAuth服务器进行交互,提供资源保护和第三方应用授权。 7. **XML和Java配置**:...
《教你使用_SpringSecurity_3.0_52页.pdf》这个文件可能是这本书的一部分,包含了52页的具体内容。虽然篇幅不长,但足以覆盖Spring Security的基本概念和用法。阅读这本书,结合实践操作,将有助于你快速掌握Spring ...