《Spring Security3》第六章第二部分翻译(自定义AuthenticationProvider)(转载)
实现自定义的AuthenticationProvider
在很多场景下,你的应用需要跳出SpringSecurity功能的边界,可能会需要实现自己的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用户的登录,我们的算法期望在请求头中包含如下的数据:
一般来讲,AuthenticationProvider将会寻找特定的AuthenticationToken,而后者会在过滤器链中位置比较靠前的servlet filter里面进行填充赋值(明确会在AuthenticationManager访问检查执行之前),如下图描述:
?
在这种方式中,AuthenticationToken的提供者与其消费者AuthenticationProvider有一点脱离关系了。所以,在实现自定义AuthenticationProvider时,通常还需要实现一个自定义的servlet过滤器,其作用是提供特定的AuthenticationToken。
自定义认证token我们实现自定义的方法会尽可能的使用SpringSecurity的基本功能。基于此,我们会扩展并增强基本类如UsernamePasswordAuthenticationToken,并添加一个新的域来存储我们已编码的签名字符串。最终的类com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationToken,如下:
?
?
在本例中,我们尽可能将错误检查最小化(译者注:即参数的合法性与完整性的检查)。可能在实际的应用中,会校验是否所有头信息都提供了以及在发现用户提供信息不正确的时候要抛出异常或对用户进行重定向。
一个细小的配置变化是需要将我们的过滤器插入到过滤器链中:
?
?
连接多个AuthenticationProvider实际上很简单。只需要在我们的dogstore-security.xml配置文件中声明另一个authentication-provider引用。
?
?
如果你能时刻记住它们的角色,当你在开发应用特定的AuthenticationProvider时,会在实现和调试过程中少很多的迷惑。