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>
至于其他的依赖属性注入就自己根据项目来添加吧,这里就不详细说明了