security的登录参数验证主要是经过UsernamePasswordAuthenticationFilter过滤器
所以我们自己写个新的实现类类继承UsernamePasswordAuthenticationFilter,验证码工具我是使用jcaptcha,相信大家对这个也不会感觉陌生吧,至于网上也有很多这样的例子来演示如何扩展了
先来写个实现类继承UsernamePasswordAuthenticationFilter
/**
* 重载SECURITY3的UsernamePasswordAuthenticationFilter的attemptAuthentication,
* obtainUsername,obtainPassword方法(完善逻辑) 增加验证码校验模块 添加验证码属性 添加验证码功能开关属性
*
* @author shadow
* @email 124010356@qq.com
* @create 2012.04.28
*/
public class UsernamePasswordAuthenticationExtendFilter extends
UsernamePasswordAuthenticationFilter {
// 验证码字段
private String validateCodeParameter = "validateCode";
// 是否开启验证码功能
private boolean openValidateCode = false;
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// 只接受POST方式传递的数据
if (!"POST".equals(request.getMethod()))
throw new MethodErrorException("不支持非POST方式的请求!");
// 开启验证码功能的情况
if (isOpenValidateCode())
checkValidateCode(request);
// 获取Username和Password
String username = obtainUsername(request);
String password = obtainPassword(request);
// UsernamePasswordAuthenticationToken实现Authentication校验
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// 允许子类设置详细属性
setDetails(request, authRequest);
// 运行UserDetailsService的loadUserByUsername 再次封装Authentication
return this.getAuthenticationManager().authenticate(authRequest);
}
// 匹对验证码的正确性
public void checkValidateCode(HttpServletRequest request) {
String jcaptchaCode = obtainValidateCodeParameter(request);
if (null == jcaptchaCode)
throw new ValidateCodeException("验证码超时,请重新获取!");
boolean b = CaptchaServiceSingleton.getInstance()
.validateResponseForID(request.getSession().getId(),
jcaptchaCode);
if (!b)
throw new ValidateCodeException("验证码不正确,请重新输入!");
}
public String obtainValidateCodeParameter(HttpServletRequest request) {
Object obj = request.getParameter(getValidateCodeParameter());
return null == obj ? "" : obj.toString().trim();
}
@Override
protected String obtainUsername(HttpServletRequest request) {
Object obj = request.getParameter(getUsernameParameter());
return null == obj ? "" : obj.toString().trim();
}
@Override
protected String obtainPassword(HttpServletRequest request) {
Object obj = request.getParameter(getPasswordParameter());
return null == obj ? "" : obj.toString().trim();
}
public String getValidateCodeParameter() {
return validateCodeParameter;
}
public void setValidateCodeParameter(String validateCodeParameter) {
this.validateCodeParameter = validateCodeParameter;
}
public boolean isOpenValidateCode() {
return openValidateCode;
}
public void setOpenValidateCode(boolean openValidateCode) {
this.openValidateCode = openValidateCode;
}
}
很明显我们在获取username跟password之前执行一个checkValidateCode()的方法,这里就是先比较验证码,如果失败就直接抛出ValidateCodeException,这个异常自己定义个,
只要继承AuthenticationException就可以了
校验成功就直接往下执行比较username,password,然后配置xml的时候class的指向就用自己新的filter,过滤链中使用新的filter替换掉UsernamePasswordAuthenticationFilter实现类的位置,下面是我自己的xml配置
过滤链里的serverCustomUsernamePasswordAuthenticationFilter实现换成是我们自己刚写的实现类,至于com.shadow.security.handler.LoginSuccessHandler和
com.shadow.security.handler.LoginFailureHandler这里自己实现一个AuthenticationSuccessHandler接口里面逻辑根据项目需求来设计