Spring Security实现图形验证码的功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Security实现图形验证码的功能相关的知识,希望对你有一定的参考价值。

一、生成图片验证码的步骤
1.根据随机数生成数字
2.将随机数存到Session中
3.将生成的图片写到接口的响应中

public class ImageCode {

    private BufferedImage image;//展示的图片
    private String code;//生成的随机数,Session
    private LocalDateTime expireTime;//过期时间
    public BufferedImage getImage() {
        return image;
    }
    public void setImage(BufferedImage image) {
        this.image = image;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public LocalDateTime getExpireTime() {
        return expireTime;
    }
    public void setExpireTime(LocalDateTime expireTime) {
        this.expireTime = expireTime;
    }

    //是否过期
    public boolean isExpried() {
        return LocalDateTime.now().isAfter(expireTime);
    }

    public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
        this.image = image;
        this.code = code;
        this.expireTime = expireTime;
    }

    //多少秒过期(60秒)
    public ImageCode(BufferedImage image, String code, int expireIn) {
        this.image = image;
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
    }
}
@RestController
public class ValidateCodeController {

    private static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";

    //操作Session的类
    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

    @GetMapping("/code/image")
    public void createCode(HttpServletRequest request,HttpServletResponse response) throws IOException {
        //1.根据随机数生成数字
        ImageCode imageCode = createImageCode(request);
        //2.将随机数存到Session中
        //把请求传递进ServletWebRequest,
        sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode);
        //3.将生成的图片写到接口的响应中
        ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());

    }

    //生成图片
    private ImageCode createImageCode(HttpServletRequest request) {
        int width = 67;
        int height = 23;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphics = image.getGraphics();
        Random random = new Random();

        graphics.setColor(getRandColor(200,250));
        graphics.fillRect(0, 0, width, height);
        graphics.setFont(new Font("Times New Roman", Font.ITALIC, 20));
        graphics.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);
            graphics.drawLine(x, y, x+xl, y+yl);
        }
        String sRand = "";
        for (int i = 0; i < 4; i++) {
            String rand = String.valueOf(random.nextInt(10));
            sRand +=rand;
            graphics.setColor(new Color(20, random.nextInt(110), 20+random.nextInt(110),20+random.nextInt(110)));
            graphics.drawString(rand, 13*i+6, 16);
        }
        graphics.dispose();
        return new ImageCode(image, sRand, 60);
    }

    //随机生成背景条纹
    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);
    }
}

前台登录页面增加图形验证码样式
技术分享图片

其次,再安全配置类;增加/code/image请求的

.antMatchers("/code/image").permitAll()

二、运行项目
技术分享图片
在点击登录按钮之前,需要处理校验码校验的逻辑这一步骤,这个步骤放在UsernamePasswordAuthenticationFilter之前,所以说,在安全配置类里面需求写一个自定义的Filter并且加在Username xx之前
技术分享图片
最后启动项目,访问:http://localhost:8080/sign.html

技术分享图片
在不输入验证码的时候,点击登录可以看到它把异常栈里面的所有错误信息都打印出来了
技术分享图片
这个并不是我们想要的,这个时候需要修改一下失败处理器AuthenticationFailureHandler
把返回所有堆栈信息的方法,改成只返回错误信息。
技术分享图片
还有一个问题,就是验证码错误的时候过滤器没有做拦截,而是继续往下走了,这个时候需要更改Filter的方法
技术分享图片

启动项目,访问:http://localhost:8080/sign.html
再不输入验证码的时候,点击登录
技术分享图片
可以直接看到错误信息
技术分享图片
同理,之后继续填写正确的验证码,则可以得到对应的用户信息
技术分享图片
输入错误,则有对应错误的消息提示,这个时候 验证码的功能才算是完成了。

以上是关于Spring Security实现图形验证码的功能的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security教程(13)---- 验证码功能的实现

Spring-Security 自定义Filter完成验证码校验

Spring Security---验证码详解

springboot集成spring security实现restful风格的登录认证 附代码

实现输入验证码的功能

Spring Security-- 验证码功能的实现