spring security3 的UserDetails的扩展怎么弄

2025年05月05日 17:58
有1个网友回答
网友(1):

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接口里面逻辑根据项目需求来设计

class="com.shadow.security.service.UsernamePasswordAuthenticationExtendFilter">
ref="authenticationManager" />
ref="concurrentSessionControlStrategy" />







class="com.shadow.security.handler.LoginSuccessHandler">




class="com.shadow.security.handler.LoginFailureHandler" />