- 浏览: 446981 次
- 性别:
- 来自: 大连
博客专栏
-
《Spring Secur...
浏览量:379441
文章分类
最新评论
-
蒙奇君杰:
必须感谢一番!!!愿开源的态度为更多的人所拥有,所 认同!
关于对《Spring Security3》一书的翻译说明 -
601235723:
bbjavaeye 写道你好,有个问题请教一下我配了<b ...
《Spring Security3》第四章第一部分翻译下(自定义的UserDetailsService) -
bay0902:
中国互联网的脊梁
Spring Security 3全文下载 -
hdcustc:
项目源码下载 微博网盘里的那个依赖文件损坏了啊 能否提供个可 ...
Spring Security 3全文下载 -
i641878506:
楼主辛苦, 可以提供原书的原项目文件的下载么
Spring Security 3全文下载
《Spring Security3》第六章第二部分翻译(自定义AuthenticationProvider)
- 博客分类:
- Spring Security
- J2EE
实现自定义的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 In Action》第三版译序
2013-07-12 12:19 2898《Spring In Action》第三 ... -
Tomcat源码解读系列(四)——Tomcat类加载机制概述
2012-09-23 22:23 10286声明:源码版本为Tomcat 6.0.35 ... -
Tomcat源码解读系列(三)——Tomcat对HTTP请求处理的整体流程
2012-09-09 22:34 6771声明:源码版本为Tomcat 6.0.35 前面的文章 ... -
Tomcat源码解读系列(二)——Tomcat的核心组成和启动过程
2012-09-02 16:59 6216声明:源码版本为Tom ... -
Tomcat源码解读系列(一)——server.xml文件的配置
2012-08-25 07:31 6290Tomcat是JEE开发人员最常用到的开发工具,在Jav ... -
Spring Security 3全文下载
2012-03-15 20:31 20109本书已经翻译完成,提供给大家下载 以下地址为ITEYE的电子 ... -
《Spring Security3》附录翻译(参考资料)
2012-02-13 22:58 6414附录:参考材料 在本附录中, ... -
《Spring Security3》第十三章翻译(迁移到Spring Security 3)
2012-02-13 22:50 5187第十三章 迁移到Spring Security 3 ... -
《Spring Security3》第十二章翻译(Spring Security扩展)
2012-02-13 22:38 7795第十二章 Spring Security扩展 ... -
《Spring Security3》第十一章(客户端证书认证)第二部分翻译
2012-02-13 22:23 4761在Spring Security中配置客户端证书认证 ... -
《Spring Security3》第十一章(客户端证书认证)第一部分翻译
2012-02-13 22:00 6120第十一章 客户端证书认证(Client Cert ... -
《Spring Security3》第十章(CAS)第二部分翻译(CAS高级配置)
2012-01-19 13:07 8572高级CAS配置 ... -
《Spring Security3》第十章(CAS)第一部分翻译(CAS基本配置)
2012-01-19 12:54 12221第十章 使用中心认证服务(CAS)进行单点登录 ... -
《Spring Security3》第九章(LDAP)第三部分翻译(LDAP明确配置)
2012-01-19 12:44 6380明确的LDAP bean配置 ... -
《Spring Security3》第九章(LDAP)第二部分翻译(LDAP高级配置)
2012-01-19 12:36 7081LDAP的高级配置 一旦我们 ... -
《Spring Security3》第九章(LDAP)第一部分翻译(LDAP基本配置)
2012-01-19 12:22 6101第九章 LDAP目录服务 在本章中,我们 ... -
《Spring Security3》第八章第三部分翻译(属性交换)
2012-01-18 15:46 2871属性交换(Attribute Exchange) ... -
《Spring Security3》第八章第二部分翻译(OpenID用户的注册)
2012-01-18 13:39 5318OpenID用户的注册问 ... -
《Spring Security3》第八章第一部分翻译(OpenID与Spring Security)
2012-01-17 22:38 7498第八章 对OpenID开放 OpenID是 ... -
《Spring Security3》第七章第三部分翻译(ACL的注意事项)
2012-01-17 22:25 2652典型ACL部署所要考虑的事情 ...
相关推荐
使用spring mvc 和spring security 完成简单的自定义登录
Spring security的完整使用范例,支持自定义密码的加密方式,以及成功,失败的处理。是一个完整可运行的工程,码云似乎还要注册。后期考虑下用码云
spring security3 中文版本
Spring Security 3.pdf Spring Security 3.pdf Spring Security 3.pdf Spring Security 3.pdf
spring security 4 小例子带自定义过滤器
SpringSecurity 之自定义用户权限信息的存取,SpringSecurity教程,用户权限信息存取
Spring Security三份资料,实战Spring Security 3.x.pdf;Spring Security 3.pdf;Spring Security使用手册.pdf
第二章:springsecurity起步 第三章:增强用户体验 第四章:凭证安全存储 第五章:精确的访问控制 第六章:高级配置和扩展 第七章:访问控制列表(ACL) 第八章:对OpenID开放 第九章:LDAP目录服务 第十章:使用...
3、Spring Security 2.x Overview 4、Dive Into Spring Security Authentication Authorization 5、Development Experiences & Demo 6、Q & A 张明星 5年以上保险、电信大中型项目开发经验,对JavaEE有较深入理解...
struts2 + spring3 + hibernate3 + spring security3 + mysql + tomcat sys_users;sys_roles;sys_authorities;sys_resources;sys_users_roles;sys_roles_authorities;sys_authorities_resources; PS:此项目运行不...
spring security spring security 中文文档
简单的 springSecurity3例子代码
主要介绍了详解spring security 配置多个AuthenticationProvider ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
项目应用到spring3,security3,hibernate4,struts2;应用中涉及到安全认证,目前项目有独立的统一认证网关,所以登录时只需要将安全认证网关的认证后信息塞到spring security中,由security3来管理用户的权限设置。...
springsecurity(用spring ibatis freemaker)实现的用户自定义的权限管理页面, 里头包括数据库脚本 和原数据 和原代码 主要参考http://blog.csdn.net/k10509806/article/details/6369131 这个人的文章做的
spring security的学习-3. 自定义数据库表结构
Spring Security in Action
(1)该项目是基于spring3+struts2+hibernate3+spring security3的权限管理项目 (2)后台我已经实现了权限管理,包括用户,角色和资源的分配。前台实现了spring security3的管理 (3)网上案例普遍是后台单一登陆。...
Spring Security3 Demo ,根据Spring Security 安全权限管理手册 整理出的例子。 通过eclipse部署。
Spring Security OAuth2.0学习笔记 什么是认证、授权、会话。 ... 基于session认证机制的运作流程。...Spring cloud Security OAuth2包括哪些组件?职责? 分布式系统认证需要解决的问题? 掌握学习方法,掌握思考方式。