Java实现图片验证码功能

news2024/11/15 11:17:59

文章目录

  • 一、背景
  • 二、实现步骤
    • 1、maven中加入依赖
    • 2、CaptchaController.java
    • 3、生成验证码配置
    • 4、CaptchaService.java接口
    • 5、CaptchaServiceImpl.java实现类
    • 6、增加验证码校验
    • 涉及文件

一、背景

在实现登录功能时,为了防止特定的程序暴力破解,一般为了安全都会在用户登录时增加otp动态验证码录。otp验证码 otp全称叫One-time Password,也称动态口令,是指计算机系统或其他数字设备上只能使用一次的密码,有效期为只有一次登录会话或很短。

常见验证码分为图片验证码和短信验证码,还有滑动窗口模块和选中指定物体验证方式。下面通过Java来实现图片验证码示例,效果如下:

在这里插入图片描述

二、实现步骤

1、maven中加入依赖

pom.xml引入依赖:

<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>
<dependency>
    <groupId>com.github.whvcse</groupId>
    <artifactId>easy-captcha</artifactId>
    <version>1.6.2</version>
</dependency>

2、CaptchaController.java

 /**
     * 验证码
     */
    @GetMapping("/captcha/digit")
    @ApiOperation(value = "获取数字验证码", notes = "获取数字验证码", tags = "验证码相关")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uuid", value = "uuid", required = true, paramType = "query")
    })
    @PassToken
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        log.info("获取验证码,uuid:{}", uuid);
        //获取图片验证码
        BufferedImage image = captchaService.getCaptcha(uuid);
        log.info("获取验证码,uuid:{},return:{}", uuid, JSON.toJSONString(image));
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

    @GetMapping("/captcha/graphics")
    @ApiOperation(value = "获取图形验证码", notes = "获取图形验证码", tags = "验证码相关")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uuid", value = "uuid", required = true, paramType = "query"),
            @ApiImplicitParam(name = "type", value = "类型 png:png gif:gif cn:中文 cngif:中文gif arithmeti:算术", required = false, paramType = "query")
    })
    public void captcha(HttpServletRequest request, HttpServletResponse response,
                        @RequestParam String uuid,
                        @RequestParam(defaultValue = "arithmeti", required = false) String type) throws Exception {
        // 设置请求头为输出图片类型
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        Captcha captcha = null;
        switch (type) {
            case "png":
                captcha = new SpecCaptcha(130, 48);
                break;
            case "gif":
                // gif类型
                captcha = new GifCaptcha(130, 48);
                break;
            case "cn":
                // 中文类型
                captcha = new ChineseCaptcha(130, 48, 5, new Font("楷体", Font.PLAIN, 28));
                break;
            case "cngif":
                // 中文gif类型
                captcha = new ChineseGifCaptcha(130, 48, 5, new Font("楷体", Font.PLAIN, 28));
                break;
            case "arithmeti":
                // 算术类型
                ArithmeticCaptcha arithmeticCaptcha = new ArithmeticCaptcha(130, 48);
                arithmeticCaptcha.setLen(3);  // 几位数运算,默认是两位
                arithmeticCaptcha.getArithmeticString();  // 获取运算的公式:3+2=?
                arithmeticCaptcha.text();  // 获取运算的结果:5
                captcha = arithmeticCaptcha;
                break;
            default:
                new SpecCaptcha(130, 48);
                break;
        }
        log.info("验证码:{}", captcha.text());
        // 设置字体
//        captcha.setFont(new Font("Verdana", Font.PLAIN, 32));  // 有默认字体,可以不用设置
        // 设置类型,纯数字、纯字母、字母数字混合
        captcha.setCharType(Captcha.TYPE_DEFAULT);

        //缓存验证码
        redisService.set(AuthKeys.AUTH_CAPTCHA, uuid, captcha.text().toLowerCase());
        // 输出图片流
        captcha.out(response.getOutputStream());
    }
}

3、生成验证码配置

/**
 * 生成验证码配置
 *
 */
@Configuration
public class KaptchaConfig {

    @Bean
    public DefaultKaptcha producer() {
        Properties properties = new Properties();
        //图片边框
        properties.setProperty("kaptcha.border", "no");
        //文本集合,验证码值从此集合中获取
        properties.setProperty("kaptcha.textproducer.char.string", "ABCDEGHJKLMNRSTUWXY23456789");
        //字体颜色
        properties.setProperty("kaptcha.textproducer.font.color", "0,84,144");
        //干扰颜色
        properties.setProperty("kaptcha.noise.color", "0,84,144");
        //字体大小
        properties.setProperty("kaptcha.textproducer.font.size", "30");
        //背景颜色渐变,开始颜色
        properties.setProperty("kaptcha.background.clear.from", "247,255,234");
        //背景颜色渐变,结束颜色
        properties.setProperty("kaptcha.background.clear.to", "247,255,234");
        //图片宽
        properties.setProperty("kaptcha.image.width", "125");
        //图片高
        properties.setProperty("kaptcha.image.height", "35");
        properties.setProperty("kaptcha.session.key", "code");
        //验证码长度
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        //字体
        properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑");
        properties.put("kaptcha.textproducer.char.space", "5");
        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

4、CaptchaService.java接口

public interface CaptchaService {
    boolean validate(String uuid, String code);
    BufferedImage getCaptcha(String uuid);
}

5、CaptchaServiceImpl.java实现类


@Service
@Slf4j
public class CaptchaServiceImpl implements CaptchaService {
    @Autowired
    private Producer producer;
    @Autowired
    private RedisService redisService;
    @Value("${default-captcha}")
    private String defaultCaptcha;
    
    /**
    * 生成并缓存验证码,返给前端图片
    */
    @Override
    public BufferedImage getCaptcha(String uuid) {
        if (StringUtils.isEmpty(uuid)) {
            throw new GlobalException(BasicCodeMsg.PARAMETER_ERROR.setMsg("uuid不能为空"));
        }
        //生成文字验证码
        String code = producer.createText();
        log.info("uuid:{},验证码:{}",uuid,code);
        //缓存验证码
        redisService.set(AuthKeys.AUTH_CAPTCHA, uuid, code);

        return producer.createImage(code);
    }
}

   /**
    * 校验验证码
    */
    @Override
    public boolean validate(String uuid, String code) {

        //测试环境123456通过验证(可不加)
        if (EnvEnum.dev.name().equals(env) && code.equals(defaultCaptcha)) {
            return true;
        }

        String cacheCode = redisService.get(AuthKeys.AUTH_CAPTCHA, uuid, String.class);
        if (StringUtils.isEmpty(cacheCode)) {
            return false;
        }
        //删除缓存验证码
        redisService.delete(AuthKeys.AUTH_CAPTCHA, uuid);
        if (cacheCode.equalsIgnoreCase(code)) {
            return true;
        }
        return false;
    }

6、增加验证码校验

在登录授权验证的地方添加验证码相关校验,也就是原来校验用户名密码的地方增加。


        if ("captcha".equals(type)) {
            LoginVo loginVo = LoginVo.builder().captcha(captcha)
                    .loginName(username)
                    .uuid(uuid).build();
            boolean result = captchaService.validate(uuid, captcha);
            if (!result) {
                throw new OAuth2Exception("验证码不正确");
            }
            return;

涉及文件

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/431138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用DevExpress22.X(Patch)控件库在VisualStudio2022使用C#进行Winform、WPF应用的开发,看这一篇就够了!

写在开头&#xff0c;Dev Express是个十分强大的控件库&#xff08;下文简称Dev&#xff09;&#xff0c;但碍于其高昂的使用费用&#xff0c;“出于学习目的”&#xff0c;我们一般使用的都是Patch版本&#xff08;在版权意识日趋加强的当下&#xff0c;不要提那两个字&#x…

面试题React

1.React Fiber是什么&#xff1f; 在 React V16 将调度算法进行了重构&#xff0c; 将之前的 stack reconciler 重构成新版的 fiber reconciler&#xff0c;变成了具有链表和指针的 单链表树遍历算法。通过指针映射&#xff0c;每个单元都记录着遍历当下的上一步与下一步&…

接口测试用例编写和接口测试模板

一、简介 接口测试区别于传统意义上的系统测试&#xff0c;下面介绍接口测试用例和接口测试报告。 二、接口测试用例模板 功能测试用例最重要的两个因素是测试步骤和预期结果&#xff0c;接口测试属于功能测试&#xff0c;所以同理。接口测试的步骤中&#xff0c;最重要的是将…

149.网络安全渗透测试—[Cobalt Strike系列]—[HTTP Beacon重定器/代理服务器/流量走向分析]

我认为&#xff0c;无论是学习安全还是从事安全的人多多少少都会有些许的情怀和使命感&#xff01;&#xff01;&#xff01; 文章目录一、Cobalt Strike 重定器1、Cobalt Strike 重定器简介2、重定器用到的端口转发工具二、cobalt strike重定器实验1、实验背景2、实验过程3、流…

Springboot项目Aop、拦截器、过滤器横向对比

前言 伟人曾经说过&#xff0c;没有调查就没有发言权(好像是伟人说的&#xff0c;不管谁说的&#xff0c;这句话是正确的)&#xff0c;有些东西看着简单&#xff0c;张口就来&#xff0c;但很有可能是错的。我个人的经验是&#xff0c;aop、过滤器、拦截器的实现方式很简单&…

冯诺依曼体系结构+操作系统

目录 冯诺依曼体系结构 基本概念 基本原理 操作系统 基本概念 设计OS的目的 管理的本质 管理的方法 系统调用和库函数 冯诺依曼体系结构 基本概念 冯诺依曼结构也称普林斯顿结构&#xff0c;是一种将程序指令存储器和数据存储器合并在一起的存储器结构。 ... 数学…

GDOUCTD NSSCTF2023广东海洋大学比赛WP RE(上) Tea Check_Your_Luck

Check_Your_Luck 下载文件是cpp 是个解方程的题&#xff0c;用python的z3 from z3 import * v,w,x,y,zBitVecs(v w x y z,16)lSolver() l.add(v * 23 w * -32 x * 98 y * 55 z * 90 333322) l.add(v * 123 w * -322 x * 68 y * 67 z * 32 707724) l.add(v * 266 …

openEuler RISC-V 23.03 创新版本亮相:全面提升硬件兼容性和桌面体验

近日&#xff0c;openEuler RISC-V 23.03 创新版本正式发布。openEuler RISC-V SIG 作为 openEuler 系统在 RISC-V 架构上的维护组织&#xff0c;主要致力于 openEuler 在 RISC-V 软硬件方面的适配&#xff0c;一直跟随 openEuler 版本节奏提供 openEuler 的 RISC-V 镜像版本。…

Redis源码之SDS简单动态字符串

Redis 是内存数据库&#xff0c;高效使用内存对 Redis 的实现来说非常重要。 看一下&#xff0c;Redis 中针对字符串结构针对内存使用效率做的设计优化。 一、SDS的结构 c语言没有string类型&#xff0c;本质是char[]数组&#xff1b;而且c语言数组创建时必须初始化大小&#…

图片转PDF怎么转换?快学习这三种免费转换方法!

图像转PDF功能是指将图像文件转换为PDF文件的过程。PDF&#xff08;PortableDocumentFormat&#xff09;它是一种文件类型&#xff0c;可以存储许多元素&#xff0c;如文本、图像和报告。PDF文档具有跨平台、可打印、可搜索等优点&#xff0c;因此广泛应用于文档共享、文档存储…

Qt扫盲-QAbstractSeries理论总结

QAbstractSeries理论总结 一、概述二、常用函数1. 属性2. 设置功能3. 显示隐藏4. 与 绘图的交互 三、信号 一、概述 QAbstractSeries类是所有Qt图表线的基类。通常&#xff0c;特定于序列类型的继承类会被使用&#xff0c;而不是这个基类。这个基类只是提供了一些管理和控制这…

多功能科学计算器:Magic Number 2 Mac中文

Magic Number Mac - 让数学更简单。当你能正确地看待数学&#xff0c;能够输入你的想法&#xff0c;并凭直觉做每件事时&#xff0c;数学就会变得轻而易举。从日常数学到高级科学&#xff0c;Magic Number 让您事半功倍——无论您的水平如何。欢迎需要的朋友下载使用&#xff0…

IDEA中使用Git提交代码

在IDEA中使用git提交代码到远程仓库&#xff0c;整体可分为如下几个步骤&#xff1a; 前提&#xff1a;注册有GitHub或者gitee账号&#xff1b;本地安装有git。 1.创建远程仓库&#xff08;github或者gitee&#xff09;&#xff1b; 2.创建本地仓库并提交代码到本地仓库&#x…

2023年如何成为一名优秀的大前端Leader?

目录 一、0-1开发vs低代码 二、优点与缺点 先以JNPF为例&#xff0c;展开说说优点&#xff1a; 1、开发周期短&#xff08;这点我愿称之为神&#xff09;&#xff1a; 2、开发成本低 3、助力企业适用市场 再来说说缺点&#xff1a; 1、平台越成熟&#xff0c;费用越高 …

【动态规划】经典问题第三组---背包问题基础

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启算法的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请收藏点赞关注支持一波, 感激不尽~~ 刷题专栏在这里~~ 简单介绍一下什么是背包问…

再学C语言50:C库中的字符串函数(2)

一、strcmp()函数 功能&#xff1a;对字符串内容进行比较&#xff0c;如果两个字符串参数相同&#xff0c;函数返回0 示例代码&#xff1a; /* test of strcmp() function */ #include <stdio.h> #include <string.h>#define NAME "Forster"int main(…

rem实现移动端自适应

rem实现自适应的原理&#xff1a;就是屏幕的宽度/任意数&#xff08;推荐设计稿除下来是整数&#xff0c;方便计算&#xff09;&#xff0c;接着设置根html的font-size为这个数&#xff0c;比如设计师给我们的设计稿宽度为750px&#xff0c;我们可以用750/7.5得到100再赋值给ht…

rnn、lstm、cnn、transformer

rnn不能并行的原因&#xff1a;不同时间步的隐藏层之间有关联。 rnn中batch的含义 如何理解RNN中的Batch_size&#xff1f;_batch rnn_Forizon的博客-CSDN博客 rnn解决的问题 不定长输入带有顺序的序列输入1 rnn前向传播 2 rnn中的反向传播 还有loss对其他参数的求导&#…

Flutter渲染原理

一 Widget Element RenderObject 之间的关系 1 Widget 在Flutter 中&#xff0c;万物皆是Widget,无论是可见的还是功能型的。一切都是Widget. 官方文档中说的Widget 使用配置和状态来描述View 界面应该长什么样子。 它不仅可以表示UI元素&#xff0c;也可以表示一些功能性的…

前端学习:HTML JavaScript

目录 一、JavaScript 使HTML页面更具有动态性和交互性 浏览器中的 JavaScript 能做什么&#xff1f; 二、 HTML三、HTML标签 ​编辑四、JavaScript 的功能示例 1. JavaScript 能够更改内容&#xff1a; 2. JavaScript能够更改样式&#xff1a;3.JavaScript能够更改属性 五、…