ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

spring security增加图形验证码

2021-09-25 13:02:45  阅读:168  来源: 互联网

标签:getSession spring imageTime request 验证码 imageCode session security public


前言

在使用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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有