spring security增加图形验证码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzl19870309/article/details/70266939

对于这个需求,网上的解决方案比较多,如使用filter、自定义Provider……
我采用方法是采用增加AuthenticationProvider的方式。具体实现如下:
1、增加WebAuthenticationDetails实现类,保存验证码信息

public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {

    private String imageCode;

    private String session_imageCode;

    private long session_imageTime;

    public CustomWebAuthenticationDetails(HttpServletRequest request) {
        super(request);
        this.imageCode = request.getParameter("imageCode");
        this.session_imageCode = (String)request.getSession().getAttribute("session_imageCode");
        String session_verifyTime = (String)request.getSession().getAttribute("session_imageTime");
        if(session_verifyTime == null) {
            this.session_imageTime= 0L;
        } else {
            this.session_imageTime= Long.parseLong(session_verifyTime);
        }
    }

    public String getImageCode(){
        return imageCode;
    }

    public String getSession_imageCode() {
        return session_imageCode;
    }

    public long getSession_imageTime() {
        return session_imageTime;
    }
}

2、增加AuthenticationDetailsSource实现类

@Component
public class CustomAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
    @Override
    public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
        return new CustomWebAuthenticationDetails(context);
    }
}

3、自定义AuthenticationProvider实现类,并添加到验证列表中去

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        CustomWebAuthenticationDetails details = (CustomWebAuthenticationDetails) authentication.getDetails();  
        String imageCode = details.getImageCode();
        String session_imageCode = details.getSession_imageCode();
        long session_imageTime = details.getSession_imageTime();

        if(imageCode == null || session_imageCode == null) {
            throw new ImageCodeIllegalException("验证码错误");
        }

        if(!imageCode.equals(session_imageCode)) {
            throw new ImageCodeIllegalException("验证码错误");
        }else{
            long nowTime = System.currentTimeMillis();
            if((nowTime - session_imageTime)/1000 > 60) { //大于60s,超时
                throw new ImageCodeIllegalException("验证码已超时");
            }
        }
       return null; //如果后续要有验证密码的provider,这里需要直接返回null
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

4、在WebSecurityConfigurerAdapter的实现类中增加配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Inject
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;

    @Inject
    private AuthenticationProvider customAuthenticationProvider;

    @Inject
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);//重点
    }

     @Override
    protected void configure(HttpSecurity http) throws Exception {
        ……
        .and()
            .formLogin()
            .loginProcessingUrl("/api/login")
            .usernameParameter("username")
            .passwordParameter("password")
           .authenticationDetailsSource(authenticationDetailsSource) //重点
           .permitAll()
        ……
    }
}

为达到“用后即焚”的效果,在登录成功、失败后续处理的类中增加了清除验证码的操作

@Component
public class AjaxAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    @Autowired
    private PasswordService passwordService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication)
        throws IOException, ServletException {

            //移除验证码
            request.getSession().removeAttribute("session_verifyObj");
            request.getSession().removeAttribute("session_verifyObjTime");
            response.setStatus(HttpServletResponse.SC_OK);
    }
}
@Component
public class AjaxAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    @Autowired
    private PasswordService passwordService;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException {

            //移除验证码
            request.getSession().removeAttribute("session_imgeCode");
            request.getSession().removeAttribute("session_imageTime");

            ……
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
    }
}

然后在WebSecurityConfigurerAdapter的实现类中增加相关配置

    ……
    .and()
    .formLogin()
    .loginProcessingUrl("/api/login")
    .successHandler(ajaxAuthenticationSuccessHandler) //重点
    .failureHandler(ajaxAuthenticationFailureHandler) //重点
    .usernameParameter("username")
    .passwordParameter("password")
    .authenticationDetailsSource(authenticationDetailsSource)
    .permitAll()
    ……

下一篇将探讨一下authenticationProvider的用法,以及当用户找不到时,不隐藏UserNotFoundException的解决办法

猜你喜欢

转载自blog.csdn.net/wzl19870309/article/details/70266939
今日推荐