其他分享
首页 > 其他分享> > spring security增加图形验证码

spring security增加图形验证码

作者:互联网

前言

在使用Spring Security框架过程中,经常会有这样的需求,即在登录验证时,附带增加额外的数据,如验证码、用户类型等。下面将介绍如何实现。
  注:我的工程是在Spring Boot框架基础上的,使用xml方式配置的话请读者自行研究吧。
实现自定义的WebAuthenticationDetails
  该类提供了获取用户登录时携带的额外信息的功能,默认实现WebAuthenticationDetails提供了remoteAddress与sessionId信息。开发者可以通过Authentication的getDetails()获取WebAuthenticationDetails。我们编写自定义类CustomWebAuthenticationDetails继承自WebAuthenticationDetails,添加我们关心的数据(以下是一个token字段)。

对于这个需求,网上的解决方案比较多,如使用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;
    }
}

注:在登录页面,可将token字段放在form表单中,也可以直接加在url的参数中,进而把额外数据发送给后台。
2、增加AuthenticationDetailsSource实现类
该接口用于在Spring Security登录过程中对用户的登录信息的详细信息进行填充,默认实现是WebAuthenticationDetailsSource,生成上面的默认实现WebAuthenticationDetails。我们编写类实现AuthenticationDetailsSource,用于生成上面自定义的CustomWebAuthenticationDetails。

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

3、自定义AuthenticationProvider实现类,并添加到验证列表中去
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()
    ……

标签:getSession,spring,imageTime,request,验证码,imageCode,session,security,public
来源: https://blog.csdn.net/ningmeng666_c/article/details/120470261