前后端分离,SpringBoot如何实现验证码操作
验证码的功能是防止非法用户恶意去访问登录接口而设置的一个功能,今天我们就来看看在前后端分离的项目中,SpringBoot是如何提供服务的。
SpringBoot版本
本文基于的Spring Boot的版本是2.6.7 。
引入依赖
captcha一款超简单的验证码生成,还挺好玩的.还有中文验证码,动态验证码. 。在项目中pom.xml配置文件中添加依赖,如下:
<!--验证码-->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
实现思路
- 把生成的验证码结果保存到redis缓存中,并设置过期时间。
- 前端通过提交验证码和key,其中key就是保存到redis中的键,通过这个键获取到对应的值,再与前端提交的值对比,相同就通过验证。
实现过程
新建验证码枚举类
由于captcha这款验证码提供了好几种验证码方法,有中文验证码,动态验证码,算术验证码等等,新建一个验证码每周类存放这几种验证码类型。代码如下:
public enum LoginCodeEnum {
/**
* 算数
*/
ARITHMETIC,
/**
* 中文
*/
CHINESE,
/**
* 中文闪图
*/
CHINESE_GIF,
/**
* 闪图
*/
GIF,
SPEC
}
定义验证码配置信息
该类是定义验证码的基本信息,例如高度、宽度、字体类型、验证码类型等等、并且我们把它转成通过SpringBoot配置文件类型来定义更加方便。
@Data
public class LoginCode {
/**
* 验证码配置
*/
private LoginCodeEnum codeType;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
/**
* 验证码字体
*/
private String fontName;
/**
* 字体大小
*/
private int fontSize = 25;
/**
* 验证码前缀
* @return
*/
private String codeKey;
public LoginCodeEnum getCodeType() {
return codeType;
}
}
把配置文件转换Pojo类的统一配置类
@Configuration
public class ConfigBeanConfiguration {
@Bean
@ConfigurationProperties(prefix = "login")
public LoginProperties loginProperties() {
return new LoginProperties();
}
}
定义验证逻辑生成类
@Data
public class LoginProperties {
private LoginCode loginCode;
/**
* 获取验证码生产类
* @return
*/
public Captcha getCaptcha(){
if(Objects.isNull(loginCode)){
loginCode = new LoginCode();
if(Objects.isNull(loginCode.getCodeType())){
loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
}
}
return switchCaptcha(loginCode);
}
/**
* 依据配置信息生产验证码
* @param loginCode
* @return
*/
private Captcha switchCaptcha(LoginCode loginCode){
Captcha captcha = null;
synchronized (this){
switch (loginCode.getCodeType()){
case ARITHMETIC:
captcha = new FixedArithmeticCaptcha(loginCode.getWidth(),loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case CHINESE:
captcha = new ChineseCaptcha(loginCode.getWidth(),loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case CHINESE_GIF:
captcha = new ChineseGifCaptcha(loginCode.getWidth(),loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case GIF:
captcha = new GifCaptcha(loginCode.getWidth(),loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case SPEC:
captcha = new SpecCaptcha(loginCode.getWidth(),loginCode.getHeight());
captcha.setLen(loginCode.getLength());
default:
System.out.println("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
}
}
if(StringUtils.isNotBlank(loginCode.getFontName())){
captcha.setFont(new Font(loginCode.getFontName(),Font.PLAIN,loginCode.getFontSize()));
}
return captcha;
}
static class FixedArithmeticCaptcha extends ArithmeticCaptcha{
public FixedArithmeticCaptcha(int width,int height){
super(width,height);
}
@Override
protected char[] alphas() {
// 生成随机数字和运算符
int n1 = num(1, 10), n2 = num(1, 10);
int opt = num(3);
// 计算结果
int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
// 转换为字符运算符
char optChar = "+-x".charAt(opt);
this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
this.chars = String.valueOf(res);
return chars.toCharArray();
}
}
}
在控制层上定义验证码生成接口
@ApiOperation(value = "获取验证码", notes = "获取验证码")
@GetMapping("/code")
public Object getCode(){
Captcha captcha = loginProperties.getCaptcha();
String uuid = "code-key-"+IdUtil.simpleUUID();
//当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型
String captchaValue = captcha.text();
if(captcha.getCharType()-1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")){
captchaValue = captchaValue.split("\\.")[0];
}
// 保存
redisUtils.set(uuid,captchaValue,loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
// 验证码信息
Map<String,Object> imgResult = new HashMap<String,Object>(2){{
put("img",captcha.toBase64());
put("uuid",uuid);
}};
return imgResult;
}
效果体验

在前端调用接口
<template>
<div class="login-code">
<img :src="codeUrl" @click="getCode">
</div>
</template>
<script>
methods: {
getCode() {
getCodeImg().then(res => {
this.codeUrl = res.data.img
this.loginForm.uuid = res.data.uuid
})
},
}
created() {
// 获取验证码
this.getCode()
},
</script>

前后端分离,SpringBoot如何实现验证码操作的更多相关文章
- springboot前后端分离项目redis做验证码及用户信息存储验证长时间不操作失效问题解决
1.错误回显:Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: MISCO ...
- vue中使用分页组件、将从数据库中查询出来的数据分页展示(前后端分离SpringBoot+Vue)
文章目录 1.看实现的效果 2.前端vue页面核心代码 2.1. 表格代码(表格样式可以去elementui组件库直接调用相应的) 2.2.分页组件代码 2.3 .script中的代码 3.后端核心代 ...
- springboot + mybatis 前后端分离项目的搭建 适合在学习中的大学生
人生如戏,戏子多半掉泪! 我是一名大四学生,刚进入一家软件件公司实习,虽说在大学中做过好多个实训项目,都是自己完成,没有组员的配合.但是在这一个月的实习中,我从以前别人教走到了现在的自学,成长很多. ...
- 前后端分离djangorestframework—— 接入第三方的验证码平台
关于验证码部分,在我这篇文章里说的挺详细的了:Python高级应用(3)—— 为你的项目添加验证码 这里还是再给一个前后端分离的实例,因为极验官网给的是用session作为验证的,而我们做前后端分离的 ...
- springboot 前后端分离开发 从零到整(三、登录以及登录状态的持续)
今天来写一下怎么登录和维持登录状态. 相信登录验证大家都比较熟悉,在Javaweb中一般保持登录状态都会用session.但如果是前后端分离的话,session的作用就没有那么明显了.对于前后端分离的 ...
- springboot 前后端分离开发 从零到整(二、邮箱注册)
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 url: ...
- shiro,基于springboot,基于前后端分离,从登录认证到鉴权,从入门到放弃
这个demo是基于springboot项目的. 名词介绍: ShiroShiro 主要分为 安全认证 和 接口授权 两个部分,其中的核心组件为 Subject. SecurityManager. Re ...
- springboot+apache前后端分离部署https
目录 1. 引言 2. 了解https.证书.openssl及keytool 2.1 https 2.1.1 什么是https 2.1.2 https解决什么问题 2.2 证书 2.2.1 证书内容 ...
- SpringBoot 和Vue前后端分离入门教程(附源码)
作者:梁小生0101 juejin.im/post/5c622fb5e51d457f9f2c2381 推荐阅读(点击即可跳转阅读) 1. SpringBoot内容聚合 2. 面试题内容聚合 3. 设计 ...
随机推荐
- 学习openstack(七)
相关资料: https://www.cnblogs.com/shhnwangjian/category/942049.html https://www.cnblogs.com/goodcook/cat ...
- 数据结构:DHU顺序表ADT模板设计及简单应用:找匹配
顺序表ADT模板设计及简单应用:找匹配 时间限制: 1S类别: DS:线性表->线性表应用 问题描述: 输入范例: 100000100000 99999 99998 99997 99996 99 ...
- JS练习实例--编写经典小游戏俄罗斯方块
最近在学习JavaScript,想编一些实例练练手,之前编了个贪吃蛇,但是实现时没有注意使用面向对象的思想,实现起来也比较简单所以就不总结了,今天就总结下俄罗斯方块小游戏的思路和实现吧(需要下载代码也 ...
- 手把手教你从零写一个简单的 VUE--模板篇
教程目录1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 Hello,我又回来了,上一次的文章教会了大家如何书写一个简单 VUE,里面实现了VUE 的数据驱动视图 ...
- 基于融云的IM通讯
一.业务场景 项目的发展需要吧原来自己的写的通讯换为第三方的,多家对比后选择了融云IM通讯,项目要实现的功能这要是单聊.群聊.聊天室.发送的内容为文字.图片.文件.语音通话与视频通话.听起来挺复杂的我 ...
- 网络安全—xss
1.xss的攻击原理 需要了解 Http cookie ajax,Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意html标签或者javascript代码.比如 ...
- 你可以说出export export default || model.exports exports 的区别吗(一)
一.前言: 用模块写代码,为什么要用模块来写代码:ES6之前,在js中定义的一切,都是共享一个全局作用域的,随着web应用变得复杂,这样做会引起如:命名冲突和安全问题.于是引入了模块. 二.清楚一个概 ...
- python爬虫---爬取网易云音乐
代码: import requests from lxml import etree text = requests.get("https://music.163.com/discover/ ...
- BootstrapBlazor 使用模板创建项目
原文连接:https://www.cnblogs.com/ysmc/p/16101157.html BootstrapBlazor 官网地址:https://www.blazor.zone Boots ...
- Vue入坑日记: day - 01
前言 最近做了一些小项目,小组里写前端的确实有点拉胯,于是自己动手写前端,因为大一学过web前端基础,所以对HTML,CSS还有印象,就直接对JS下手了,学了两天把JS大致搞明白了,顺便对JQuery ...