栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Security实现验证码登录功能

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Security实现验证码登录功能

这篇文章主要介绍了Spring Security实现验证码登录功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

在spring security实现登录注销功能的基础上进行开发。

1、添加生成验证码的控制器。

(1)、生成验证码


  @Autowired
  private SecurityProperties securityProperties;


  @Override
  public ImageCode createCode(HttpServletRequest request ) {
    //如果请求中有 width 参数,则用请求中的,否则用 配置属性中的
    int width = ServletRequestUtils.getIntParameter(request,"width",securityProperties.getWidth());
    //高度(宽度)
    int height = ServletRequestUtils.getIntParameter(request,"height",securityProperties.getHeight());
    //图片验证码字符个数
    int length = securityProperties.getLength();
    //过期时间
    int expireIn = securityProperties.getExpireIn();

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

    Graphics g = image.getGraphics();

    Random random = new Random();

    g.setColor(getRandColor(200, 250));
    g.fillRect(0, 0, width, height);
    g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
    g.setColor(getRandColor(160, 200));
    for (int i = 0; i < 155; i++) {
      int x = random.nextInt(width);
      int y = random.nextInt(height);
      int xl = random.nextInt(12);
      int yl = random.nextInt(12);
      g.drawLine(x, y, x + xl, y + yl);
    }

    String sRand = "";
    for (int i = 0; i < length; i++) {
      String rand = String.valueOf(random.nextInt(10));
      sRand += rand;
      g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
      g.drawString(rand, 13 * i + 6, 16);
    }

    g.dispose();

    return new ImageCode(image, sRand, expireIn);
  }

  
  private Color getRandColor(int fc, int bc) {
    Random random = new Random();
    if (fc > 255) {
      fc = 255;
    }
    if (bc > 255) {
      bc = 255;
    }
    int r = fc + random.nextInt(bc - fc);
    int g = fc + random.nextInt(bc - fc);
    int b = fc + random.nextInt(bc - fc);
    return new Color(r, g, b);
  }

(2)、验证码控制器

public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";

  @Autowired
  private ValidateCodeGenerator imageCodeGenerator;

  
  private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

  @GetMapping("/code/image")
  public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ImageCode imageCode = imageCodeGenerator.createCode(request);
    //将随机数 放到Session中
    sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY,imageCode);
    request.getSession().setAttribute(SESSION_KEY,imageCode);
    //写给response 响应
    response.setHeader("Cache-Control", "no-store, no-cache");
    response.setContentType("image/jpeg");
    ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream());
  }

(3)、其它辅助类

@Data
public class ImageCode {

  
  private BufferedImage image;
  
  private String code;
  
  private LocalDateTime expireTime;

  public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
    this.image = image;
    this.code = code;
    this.expireTime = expireTime;
  }
  public ImageCode(BufferedImage image, String code, int expireIn) {
    this.image = image;
    this.code = code;
    //当前时间 加上 设置过期的时间
    this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
  }

  public boolean isExpried(){
    //如果 过期时间 在 当前日期 之前,则验证码过期
    return LocalDateTime.now().isAfter(expireTime);
  }
}
@ConfigurationProperties(prefix = "sso.security.code.image")
@Component
@Data
public class SecurityProperties {

  
  private int width = 67;
  
  private int height = 23;
  
  private int length = 4;
  
  private int expireIn = 60;

  
  private String url;
}

(4)、验证

2、添加过滤器,进行验证码验证

@Component
@Slf4j
public class ValidateCodeFilter extends oncePerRequestFilter implements InitializingBean {

  
  @Autowired
  private AuthenticationFailureHandler failureHandler;
  
  private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

  
  private Set urls = new HashSet<>();
  
  private AntPathMatcher pathMatcher = new AntPathMatcher();

  @Autowired
  private SecurityProperties securityProperties;
  
  @Override
  public void afterPropertiesSet() throws ServletException {
    super.afterPropertiesSet();
    //将 application 配置中的 url 属性进行 切割
    String[] configUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getUrl(), ",");
    //添加到 Set 集合里
    urls.addAll(Arrays.asList(configUrls));
    //因为登录请求一定要有验证码 ,所以直接 add 到set 集合中
    urls.add("/authentication/form");
  }

  @Override
  protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

    boolean action = false;
    for (String url:urls){
      //如果请求的url 和 配置中的url 相匹配
      if (pathMatcher.match(url,httpServletRequest.getRequestURI())){
 action = true;
      }
    }

    //拦截请求
    if (action){
      logger.info("拦截成功"+httpServletRequest.getRequestURI());
      //如果是登录请求
      try {
 validate(new ServletWebRequest(httpServletRequest));
      }catch (ValidateCodeException exception){
 //返回错误信息给 失败处理器
 failureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,exception);
 return;
      }

    }
    filterChain.doFilter(httpServletRequest,httpServletResponse);

  }
  private void validate(ServletWebRequest request) throws ServletRequestBindingException {
    //从session中取出 验证码
    ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request,ValidateCodeController.SESSION_KEY);
    //从request 请求中 取出 验证码
    String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),"imageCode");

    if (StringUtils.isBlank(codeInRequest)){
      logger.info("验证码不能为空");
      throw new ValidateCodeException("验证码不能为空");
    }
    if (codeInSession == null){
      logger.info("验证码不存在");
      throw new ValidateCodeException("验证码不存在");
    }
    if (codeInSession.isExpried()){
      logger.info("验证码已过期");
      sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
      throw new ValidateCodeException("验证码已过期");
    }
    if (!StringUtils.equals(codeInSession.getCode(),codeInRequest)){
      logger.info("验证码不匹配"+"codeInSession:"+codeInSession.getCode() +", codeInRequest:"+codeInRequest);
      throw new ValidateCodeException("验证码不匹配");
    }
    //把对应 的 session信息 删掉
    sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
  }

3、在核心配置BrowserSecurityConfig中添加过滤器配置

@Autowired
  private ValidateCodeFilter validateCodeFilter;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    //在UsernamePasswordAuthenticationFilter 过滤器前 加一个过滤器 来搞验证码
    http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
 //表单登录 方式
 .formLogin()
 .loginPage("/authentication/require")
 //登录需要经过的url请求
 .loginProcessingUrl("/authentication/form")
 .passwordParameter("pwd")
 .usernameParameter("user")
 .successHandler(mySuccessHandler)
 .failureHandler(myFailHandler)
 .and()
 //请求授权
 .authorizeRequests()
 //不需要权限认证的url
 .antMatchers("/authentication/*","/code/image").permitAll()
 //任何请求
 .anyRequest()
 //需要身份认证
 .authenticated()
 .and()
 //关闭跨站请求防护
 .csrf().disable();
    //默认注销地址:/logout
    http.logout().
 //注销之后 跳转的页面
 logoutSuccessUrl("/authentication/require");
  }

4、异常辅助类

public class ValidateCodeException extends AuthenticationException {
  public ValidateCodeException(String msg, Throwable t) {
    super(msg, t);
  }

  public ValidateCodeException(String msg) {
    super(msg);
  }
}

5、测试

(1)、不输入验证码

(2)、添加验证码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/135479.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号