整合Spring Security自定义登录的简便方法

安全开源框架这块咱们基本上没什么选择,Spring Security是最常用的了,虽然它功能强大,但是还是过于复杂了。虽然3.0提供了auto config,但本质上它的复杂度没有降低,只是简化了一下配置而已。我始终认为它应该弄一个简化版,不要集成那么多的认证支撑,让人一看就懂的那种,个人意见哈。

我们最常用的基于用户名和密码的认证,SS提供了UsernamePasswordAuthenticationFilter,要求我们通过POST提交j_username/j_password两个参数来完成这个认证。这个设计真是相当别扭,从它的前身Acegi开始就这样了,这不符合我们最常用的开发需求,例如我们通常会加入一个验证码什么的。

网上有两种集成方案:

1. 自己实现一个验证码的Filter插入到UsernamePasswordAuthenticationFilter前面。

2. 重写一个UsernamePasswordAuthenticationFilter,加入验证码验证,修改配置替换原来的Filter。

虽然比较符合SS的扩展模式,但个人感觉还是太麻烦了。

我想了两种比较简单的方案,思路是这样的:

1. 先自己处理验证码,然后将请求转发给UsernamePasswordAuthenticationFilter进行登录。

2. 自己处理登录过程,登录表单则可以完全自己定义了。

第一种方案

仍要保持j_username和j_password两个参数名不变,因为SS没提供该参数名的可配置项。以Struts为例子来讲,首先表单提交到我们自定义的Action方法中,这时我们可以处理验证码。验证码验证通过后,将请求转发到 /j_spring_security_check即UsernamePasswordAuthenticationFilter。这里必须是RequestDispatcher的forward方式转发,因为这样才能将j_username和j_password参数带过去。

另外我们需要在web.xml中将SS的DelegatingFilterProxy配置为支持forward转发拦截的,因为默认配置只支持request拦截。

就这样,你想在验证用户之前干点啥都可以,自己在Action中处理吧。没有侵入性,就是参数名有点受限制。

第二种方案

SS的基本原理是在ThreadLocal线程变量中存入一个SecurityContext对象,在web中通过Filter不断的传递这个线程变量,使得web的一个线程范围内的程序都可以访问到这个SecurityContext对象。这个SecurityContext对象中存有一个Authentication对象,身份和权限都在这个Authentication对象中。第二种方案就是绕开SS的Filter手动的完成验证并设置Authentication对象。关键代码如下:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,password);
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);

 authenticationManager是SS内置的一个组件,你需要定义一个别名进行注入引用。authenticationManager.authenticate(token)方法会抛出异常,你可以捕获处理这些异常,例如用户名密码错误、用户被禁用等等。在这种方案下你爱怎么自定义登录过程都可以了。

猜你喜欢

转载自jnoee.iteye.com/blog/1452380