5 分钟快速上手图形验证码,防止接口被恶意刷量!

5 分钟快速上手图形验证码,防止接口被恶意刷量!

大家好,我是程序员小白条,今天来给大家介绍一个快速实现图形验证码的优秀框架 AJ-Captcha。

需求分析

如果注册接口没有验证码这种类型的限制,很容易会被刷量,因此,一般都会使用邮箱验证码或者图形验证码进行限制,防止被恶意刷接口。邮箱验证码比较容易的是 QQ 验证码,直接配合 SpringMail 即可实现,本文主要实现图形验证码。

文字验证如下

滑动验证如下

后端

1)pom.xml 引入官方依赖包

<!-- 接入滑动验证 https://ajcaptcha.beliefteam.cn/captcha-doc/captchaDoc/java.html-->
<dependency><groupId>com.anji-plus</groupId><artifactId>spring-boot-starter-captcha</artifactId><version>1.3.0</version>
</dependency>

2)设置配置文件 properties 或者 yml 格式

# 滑动验证,底图路径,不配置将使用默认图片
# 支持全路径
# 支持项目路径,以classpath:开头,取resource目录下路径,例:classpath:images/jigsaw
aj:captcha:
#    jigsaw: "classpath:images/jigsaw"#滑动验证,底图路径,不配置将使用默认图片##支持全路径# 支持项目路径,以classpath:开头,取resource目录下路径,例:classpath:images/pic-click
#    pic-click: "classpath:images/pic-click"# 对于分布式部署的应用,我们建议应用自己实现CaptchaCacheService,比如用Redis或者memcache,# 参考CaptchaCacheServiceRedisImpl.java# 如果应用是单点的,也没有使用redis,那默认使用内存。# 内存缓存只适合单节点部署的应用,否则验证码生产与验证在节点之间信息不同步,导致失败。# !!! 注意啦,如果应用有使用spring-boot-starter-data-redis,# 请打开CaptchaCacheServiceRedisImpl.java注释。# redis ----->  SPI: 在resources目录新建META-INF.services文件夹(两层),参考当前服务resources。# 缓存local/redis...cache-type: local# local缓存的阈值,达到这个值,清除缓存#cache-number: 1000# local定时清除过期缓存(单位秒),设置为0代表不执行#timing-clear: 180#spring.redis.host: 10.108.11.46#spring.redis.port: 6379#spring.redis.password:#spring.redis.database: 2#spring.redis.timeout: 6000# 验证码类型default两种都实例化。type: default# 汉字统一使用Unicode,保证程序通过@value读取到是中文,可通过这个在线转换;yml格式不需要转换# https://tool.chinaz.com/tools/unicode.aspx 中文转Unicode# 右下角水印文字(我的水印)water-mark: "\u6211\u7684\u6c34\u5370"# 右下角水印字体(不配置时,默认使用文泉驿正黑)# 由于宋体等涉及到版权,我们jar中内置了开源字体【文泉驿正黑】# 方式一:直接配置OS层的现有的字体名称,比如:宋体# 方式二:自定义特定字体,请将字体放到工程resources下fonts文件夹,支持ttf\ttc\otf字体#water-font: WenQuanZhengHei.ttf# 点选文字验证码的文字字体(文泉驿正黑)#font-type: WenQuanZhengHei.ttf# 校验滑动拼图允许误差偏移量(默认5像素)slip-offset: 5# aes加密坐标开启或者禁用(true|false)aes-status: true# 滑动干扰项(0/1/2)interference-options: 2#点选字体样式 默认Font.BOLDfont-style: 1#点选字体字体大小font-size: 25#点选文字个数,存在问题,暂不支持修改#click-word-count: 4history-data-clear-enable: false# 接口请求次数一分钟限制是否开启 true|falsereq-frequency-limit-enable: false# 验证失败5次,get接口锁定req-get-lock-limit: 5# 验证失败后,锁定时间间隔,sreq-get-lock-seconds: 360# get接口一分钟内请求数限制req-get-minute-limit: 30# check接口一分钟内请求数限制req-check-minute-limit: 60# verify接口一分钟内请求数限制req-verify-minute-limit: 60

3)创建一个配置类,让 SpringBoot 启动时,扫描到即可

@Configuration
public class CaptchaConfig {@Bean(name = "CaptchaCacheService")@Primarypublic CaptchaCacheService captchaCacheService(AjCaptchaProperties config){//缓存类型redis/local/....CaptchaCacheService ret = CaptchaServiceFactory.getCache(config.getCacheType().name());return ret;}
}

4)创建默认实现类,跟 application.yml 的配置有关

public class DefaultCaptchaServiceImpl extends AbstractCaptchaService {DefaultCaptchaServiceImpl() {//document why this constructor is empty}//这个需要实现,如果返回 redis 那就是使用 redis 那套public String captchaType() {return "default";}@Overridepublic void init(Properties config) {for (String s : CaptchaServiceFactory.instances.keySet()) {if (!this.captchaType().equals(s)) {this.getService(s).init(config);}}}@Overridepublic void destroy(Properties config) {for (String s : CaptchaServiceFactory.instances.keySet()) {if (!this.captchaType().equals(s)) {this.getService(s).destroy(config);}}}private CaptchaService getService(String captchaType) {return CaptchaServiceFactory.instances.get(captchaType);}@Overridepublic ResponseModel get(CaptchaVO captchaVO) {if (captchaVO == null) {return RepCodeEnum.NULL_ERROR.parseError("captchaVO");} else {return StringUtils.isEmpty(captchaVO.getCaptchaType()) ? RepCodeEnum.NULL_ERROR.parseError("类型") : this.getService(captchaVO.getCaptchaType()).get(captchaVO);}}@Overridepublic ResponseModel check(CaptchaVO captchaVO) {if (captchaVO == null) {return RepCodeEnum.NULL_ERROR.parseError("captchaVO");} else if (StringUtils.isEmpty(captchaVO.getCaptchaType())) {return RepCodeEnum.NULL_ERROR.parseError("类型");} else {return StringUtils.isEmpty(captchaVO.getToken()) ? RepCodeEnum.NULL_ERROR.parseError("token") : this.getService(captchaVO.getCaptchaType()).check(captchaVO);}}@Overridepublic ResponseModel verification(CaptchaVO captchaVO) {if (captchaVO == null) {return RepCodeEnum.NULL_ERROR.parseError("captchaVO");} else if (StringUtils.isEmpty(captchaVO.getCaptchaVerification())) {return RepCodeEnum.NULL_ERROR.parseError("二次校验参数");} else {try {String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);}CaptchaServiceFactory.getCache(cacheType).delete(codeKey);} catch (Exception var3) {this.logger.error("验证码坐标解析失败", var3);return ResponseModel.errorMsg(var3.getMessage());}return ResponseModel.success();}}
}
后端接口

获取验证码接口:http://你的项目地址/captcha/get

请求参数:

{"captchaType": "blockPuzzle",  //验证码类型 clickWord"clientUid": "唯一标识"  //客户端UI组件id,组件初始化时设置一次,UUID(非必传参数)
}

响应参数:

{"repCode": "0000","repData": {"originalImageBase64": "底图base64","point": {    //默认不返回的,校验的就是该坐标信息,允许误差范围"x": 205,"y": 5},"jigsawImageBase64": "滑块图base64","token": "71dd26999e314f9abb0c635336976635", //一次校验唯一标识"secretKey": "16位随机字符串", //aes秘钥,开关控制,前端根据此值决定是否加密"result": false,"opAdmin": false},"success": true,"error": false
}

核对验证码接口接口:http://:/captcha/check

请求参数:

{"captchaType": "blockPuzzle","pointJson": "QxIVdlJoWUi04iM+65hTow==",  //aes加密坐标信息"token": "71dd26999e314f9abb0c635336976635"  //get请求返回的token
}

响应参数:

{"repCode": "0000","repData": {"captchaType": "blockPuzzle","token": "71dd26999e314f9abb0c635336976635","result": true,"opAdmin": false},"success": true,"error": false
}

5)完成前面四步后,即可测试接口是否成功被调用,可以用 postman 或者 apifox 等测试工具。

6)在用户注册的 dto 实体类加入新字段 captchaVerification。

@Data
public class UserRegisterRequest implements Serializable {private static final long serialVersionUID = 3191241716373120793L;private String userAccount;private String userPassword;private String checkPassword;private String captchaVerification;}

7)在注册接口,加上检验图形验证码的服务。

先自动注入依赖

@Resource
private CaptchaService captchaService;

再加上这段代码即可

		CaptchaVO captchaVO = new CaptchaVO();captchaVO.setCaptchaVerification(userRegisterRequest.getCaptchaVerification());ResponseModel response = captchaService.verification(captchaVO);if(!response.isSuccess()) {//验证码校验失败,返回信息告诉前端//repCode  0000  无异常,代表成功//repCode  9999  服务器内部异常//repCode  0011  参数不能为空//repCode  6110  验证码已失效,请重新获取//repCode  6111  验证失败//repCode  6112  获取验证码失败,请联系管理员throw new BusinessException(ErrorCode.FORBIDDEN_ERROR, "验证码错误请重试");}

前端

1)引入依赖

npm install aj-captcha-react

2)定义一个函数

 const ref = useRef();const click = () => {ref.current?.verify();console.log(ref.current?.verify());};

3)使用组件,这边 valueData 就是注册时带的数据,注意:path 是项目的前缀路径,你的项目可能是 8101 端口,这边是 8204 端口,api 是项目的前缀!

const [valueData, setValueData] = useState<API.UserRegisterRequest>();
<Captcha
onSuccess={async (data) => {const value = valueData;if (value) {value.captchaVerification = data.captchaVerification;await handleSubmit(value);}
}}
path="http://localhost:8204/api"
type="auto"
ref={ref}></Captcha>

完整 tsx 代码如下

const Register: React.FC = () => {const ref = useRef();const click = () => {ref.current?.verify();console.log(ref.current?.verify());};const [type, setType] = useState<string>('register');const containerClassName = useEmotionCss(() => {return {display: 'flex',flexDirection: 'column',height: '100vh',overflow: 'auto',backgroundImage:"url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",backgroundSize: '100% 100%',};});const [valueData, setValueData] = useState<API.UserRegisterRequest>();const handleSubmit = async (values: API.UserRegisterRequest) => {// 1.先判断两次输入的密码是否一致const {userPassword, checkPassword} = values;if (userPassword != checkPassword) {return message.info("两次输入的密码不一致", 1.5)}// 2.密码一致const res =  await userRegister(values);if(res.code !== 0){return message.error(res.message+"-注册失败,请重试",1.5)}message.success('注册成功,请登录账号',1.5);history.push('/user/login');};return (<div className={containerClassName}><Helmet><title>{Settings.title}</title></Helmet><divstyle={{flex: '1',padding: '32px 0',}}><LoginFormsubmitter={{searchConfig: {submitText: '注册',},}}contentStyle={{minWidth: 280,maxWidth: '75vw',}}logo={<img alt="logo" style={{height: '100%'}} src="/logo.svg"/>}title="小白条前端模板"subTitle={'快速开发属于自己的前端项目'}initialValues={{autoLogin: true,}}onFinish={async (values) => {click();setValueData(values);}}><TabsactiveKey={type}onChange={setType}centereditems={[{key: 'register',label: '用户注册',},]}/>{type === 'register' && (<><ProFormTextname="userAccount"fieldProps={{size: 'large',prefix: <UserOutlined/>,}}placeholder={'请输入账号'}rules={[{required: true,message: '账号是必填项!',},{min: 6,type: 'string',message: '长度不能小于 6',},]}/><ProFormText.Passwordname="userPassword"fieldProps={{size: 'large',prefix: <LockOutlined/>,}}placeholder={'请输入密码'}rules={[{required: true,message: '密码是必填项!',},{min: 8,type: 'string',message: '长度不能小于 8',},]}/><ProFormText.Passwordname="checkPassword"fieldProps={{size: 'large',prefix: <LockOutlined/>,}}placeholder="请再次输入密码"rules={[{required: true,message: '确认密码是必填项!',},{min: 8,type: 'string',message: '长度不能小于 8',},]}/></>)}<divstyle={{marginBottom: 24,textAlign: 'right',}}><a onClick={() => {history.push("/user/login")}}>用户登录</a></div><CaptchaonSuccess={async (data) => {const value = valueData;if (value) {value.captchaVerification = data.captchaVerification;await handleSubmit(value);}}}path="http://localhost:8102/api"type="auto"ref={ref}></Captcha></LoginForm></div><Footer/></div>);
};
export default Register;

完成之后即可看到效果图,可以自定义水印和图片,具体可以看官方文档。

官方文档地址:https://ajcaptcha.beliefteam.cn/captcha-doc/

我的 GitHub 地址:https://github.com/luoye6

个人项目:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

欢迎 Follow 💕 和 Star~⭐

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

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

相关文章

protobuf —— 快速上手

protobuf —— 快速上手 创建 .proto 文件添加注释指定proto3语法package 声明符定义消息&#xff08;message&#xff09; 定义消息字段字段定义基本格式字段名称命名规范字段类型字段唯一编号示例 转换关系示例&#xff1a;增加姓名和年龄字段 字段唯一编号字段编号范围编码效…

英伟达SSD视觉算法,jetson.inference在jetson nano中部署

一、用官方镜像刷机 安装SD卡擦除工具SD Card Formatter https://www.sdcardformatter.com/download/ 格式化SD卡 下载官方镜像 https://developer.nvidia.com/jetson-nano-sd-card-image 安装刷机工具balenaEtcher https://www.balena.io/etcher 将上面下载的镜像压缩包解…

spark的简单学习二

一 spark sql基础 1.1 Dataframe 1.介绍&#xff1a; DataFrame也是一个分布式数据容器。然而DataFrame更像传统数据库的二维表 格&#xff0c;除了数据以外&#xff0c;还掌握数据的结构信息&#xff0c;即schema。同时&#xff0c;与Hive类似&#xff0c;DataFrame也支 持…

gin框架精通篇(二)

原生数据库使用 导入模块&#xff1a;go get -u github.com/go-sql-driver/mysql 安装 mysql 数据库 安装数据库可能遇到的问题&#xff1a;&#xff08;网上的方法基本可以解决&#xff09; ERROR 1045 (28000): Access denied for user ‘-root’‘localhost’ (using passwo…

HTML 页面布局

慢慢生活&#xff0c;慢慢变好 —— 24.5.28 页面布局 盒子: 页面中所有的元素(标签)&#xff0c;都可以看做是一个盒子&#xff0c;由盒子将页面中的元素包含在一个矩形区域内&#xff0c;通过盒子的视角更方便的进行页面布局 盒子模型组成: 内容区域(content)、内边距区域(pa…

数据结构的希尔排序(c语言版)

一.希尔排序的概念 1.希尔排序的基本思想 希尔排序是一种基于插入排序算法的优化排序方法。它的基本思想如下: 选择一个增量序列 t1&#xff0c;t2&#xff0c;......&#xff0c;tk&#xff0c;其中 ti > tj, 当 i < j&#xff0c;并且 tk 1。 按增量序列个数k&#…

Centos安装,window、ubuntus双系统基础上安装Centos安装

文章目录 前言一、准备工作二、开始安装1、2、首先选择DATE&TIME2、选择最小安装3、 选择安装位置 总结 前言 因工作需要&#xff0c;我需要在工控机上额外装Centos7系统&#xff0c;不过我是装在机械硬盘上了不知道对性能是否有影响&#xff0c;若有影响&#xff0c;后面…

基于C#开发web网页管理系统模板流程-主界面管理员入库和出库功能完善

前言 紧接上篇->基于C#开发web网页管理系统模板流程-主界面管理员录入和编辑功能完善-CSDN博客 本篇将完善主界面的管理员入库和出库功能&#xff0c;同样的&#xff0c;管理员入库和出库的设计套路适用于动态表的录入和编辑 首先还是介绍一下本项目将要实现的功能 &#xf…

[Android]项目打包APK时报错PKCS12 keystore not in version 3 format

报错&#xff1a; PKCS12 keystore not in version 3 format Execution failed for task :app:packageRelease. > A failure occurred while executing com.android.build.gradle.tasks.PackageAndroidArtifact$IncrementalSplitterRunnable > com.android.ide.commo…

如何为个人网站部署SSL安全证书,以实现网站的 HTTPS 加密协议访问?

哈喽&#xff0c;大家好呀&#xff01;这里是码农后端。完成了域名的备案与解析后&#xff0c;就可以通过域名来访问我们的网站了。本篇将介绍如何为我们的网站部署SSL安全证书&#xff0c;实现网站的 HTTPS 加密协议访问。 1、购买SSL证书 未进行SSL证书部署&#xff0c;访问网…

回答篇二:测试开发高频面试题目

引用之前文章&#xff1a;测试开发高频面试题目 本篇文章是回答篇&#xff08;持续更新中&#xff09; 1. 在测试开发中使用哪些自动化测试工具和框架&#xff1f;介绍一下你对其中一个工具或框架的经验。 a. 测试中经常是用的自动化测试工具和框架有Selenium、Pytest、Postman…

调整表格大小

方法一&#xff1a;使用鼠标拖动表格边框或右下角的调整控点 在Word文档中&#xff0c;选中要缩小的表格&#xff0c;将鼠标指针放在表格的边框线上&#xff0c;直到指针变成双箭头的形状。 按住鼠标左键&#xff0c;拖动边框线&#xff0c;调整表格的宽度或高度。如果同时按住…

AI视频教程下载:使用ChatGPT进行商务写作

你将学到什么&#xff1f; 学习如何将ChatGPT集成到你的写作过程中&#xff0c;并有效地将其用作商务写作的个人写作助手。 学习如何使用ChatGPT生成想法&#xff0c;提高你的书面沟通的结构、清晰度和连贯性。 你将学习使用ChatGPT的最佳实践&#xff0c;包括如何自定义其设…

Win10版本TDengine使用分享

软件介绍 TDengine是一款开源、高性能、可扩展的时间序列数据库&#xff08;TSDB&#xff09;。它由涛思数据公司开发&#xff0c;专为处理大规模时间序列数据而设计。时间序列数据是指按时间顺序排列的数据点序列&#xff0c;广泛应用于物联网、大数据分析、金融等领域。TDen…

Redis解决缓存一致性问题

文章目录 ☃️概述☃️数据库和缓存不一致采用什么方案☃️代码实现☃️其他 ☃️概述 由于我们的 缓存的数据源来自于数据库, 而数据库的 数据是会发生变化的, 因此,如果当数据库中 数据发生变化,而缓存却没有同步, 此时就会有 一致性问题存在, 其后果是: 用户使用缓存中的过…

DSP6657 GPIO中断学习

1 简介 使用创龙板卡的KEY2按键通过中断的方式控制LED3的亮灭 2 中断学习 在C665x设备上&#xff0c;CPU中断是通过C66x CorePac中断控制器进行配置的。该中断控制器允许最多128个系统事件被编程到任意12个CPU可屏蔽中断输入&#xff08;CPUINT4至CPUINT15&#xff09;、CPU…

短剧解说一键生成原创文案的快速方法

如今短剧创作火的一塌糊涂&#xff0c;它们以其简洁明了的剧情、生动有趣的角色和紧凑的节奏&#xff0c;吸引了大量观众的关注。因此&#xff0c;它所带来的流量是非常巨大&#xff0c;不少人将流量的获取瞄准了短剧创作领域以及短剧解说领域。而对于短剧解说人员来讲&#xf…

微服务项目收获和总结---第5天(定时发布)

延迟任务 目录 延迟任务技术对比&#xff1a; Redis实现定时任务&#xff1a;​编辑新增任务&#xff1a;取消任务&#xff1a;拉取任务&#xff1a;Zset定时刷新数据到List中&#xff1a;分布式锁实现定时任务只刷新一次&#xff1a; 技术对比&#xff1a; Redis实现定时任…

香橙派 AIpro 昇腾 Ascend C++ 分类模型适配

香橙派 AIpro 昇腾 Ascend C 分类模型适配 flyfish 文章目录 香橙派 AIpro 昇腾 Ascend C 分类模型适配前言一、PyTorch官网resnet模型处理方式1、PyTorch模型 导出 onnx格式2、完整测试 输出top1结果3、完整测试 输出top5结果 二、YOLOv8官网resnet模型Python处理方式三、昇腾…

云衔科技:为什么推荐使用zoho crm客户管理系统?

在当今快速变化的商业环境中&#xff0c;企业对高效、智能化的客户关系管理&#xff08;CRM&#xff09;系统的需求日益增长。Zoho CRM&#xff0c;作为全球领先的企业级CRM解决方案提供商&#xff0c;凭借其全面的功能、高度的可定制性、以及无缝集成的生态系统&#xff0c;成…