本文章摘编、转载需要注明来源 http://write.blog.csdn.net/postedit/8575482
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接口里面逻辑根据项目需求来设计
<!-- 登录认证过滤器--> <bean id="usernamePasswordAuthenticationFilter" class="com.shadow.security.service.UsernamePasswordAuthenticationExtendFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="sessionAuthenticationStrategy" ref="concurrentSessionControlStrategy" /> <property name="usernameParameter" value="username" /> <property name="passwordParameter" value="password" /> <property name="validateCodeParameter" value="validateCode" /> <property name="openValidateCode" value="true" /> <property name="filterProcessesUrl" value="/login" /> <property name="rememberMeServices" ref="rememberMeServices" /> <property name="authenticationSuccessHandler"> <bean class="com.shadow.security.handler.LoginSuccessHandler"> <property name="indexUrl" value="/index.jsp" /> </bean> </property> <property name="authenticationFailureHandler"> <bean class="com.shadow.security.handler.LoginFailureHandler" /> </property> </bean>