前后端分离,SpringBoot如何实现验证码操作

虚幻大学 虚幻 140℃ 0评论

? 优质资源分享 ?

学习路线指引(点击解锁) 知识定位 人群定位
? Python实战微信订餐小程序 ? 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
?Python量化交易实战? 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

验证码的功能是防止非法用户恶意去访问登录接口而设置的一个功能,今天我们就来看看在前后端分离的项目中,SpringBoot是如何提供服务的。

1|*0***SpringBoot版本**

本文基于的Spring Boot的版本是2.6.7 。

2|*0***引入依赖**

captcha一款超简单的验证码生成,还挺好玩的.还有中文验证码,动态验证码. 。在项目中pom.xml配置文件中添加依赖,如下:


 com.github.whvcse
 easy-captcha
 1.6.2

3|*0***实现思路**

  • 把生成的验证码结果保存到redis缓存中,并设置过期时间。
  • 前端通过提交验证码和key,其中key就是保存到redis中的键,通过这个键获取到对应的值,再与前端提交的值对比,相同就通过验证。

3|*1***实现过程**

1|*0***新建验证码枚举类**

由于captcha这款验证码提供了好几种验证码方法,有中文验证码,动态验证码,算术验证码等等,新建一个验证码每周类存放这几种验证码类型。代码如下:

public enum LoginCodeEnum {
 /**
 * 算数
 */
 ARITHMETIC,
 /**
 * 中文
 */
 CHINESE,
 /**
 * 中文闪图
 */
 CHINESE\_GIF,
 /**
 * 闪图
 */
 GIF,
 SPEC
}

1|*0***定义验证码配置信息**

该类是定义验证码的基本信息,例如高度、宽度、字体类型、验证码类型等等、并且我们把它转成通过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();
 }
}

1|*0***定义验证逻辑生成类**

@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();
 }
 }
}

1|*0***在控制层上定义验证码生成接口**

 @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 imgResult = new HashMap(2){{
 put("img",captcha.toBase64());
 put("uuid",uuid);
 }};
 return imgResult;

 }

1|*0***效果体验**

a68efd487622a294ec58747abd9c11ad - 前后端分离,SpringBoot如何实现验证码操作

1|*0***在前端调用接口**


 ![]()

<code-line class="line-numbers-rows"></code-line> methods: {
<code-line class="line-numbers-rows"></code-line> getCode() {
<code-line class="line-numbers-rows"></code-line> getCodeImg().then(res => {
<code-line class="line-numbers-rows"></code-line> this.codeUrl = res.data.img
<code-line class="line-numbers-rows"></code-line> this.loginForm.uuid = res.data.uuid
<code-line class="line-numbers-rows"></code-line> })
<code-line class="line-numbers-rows"></code-line> },
<code-line class="line-numbers-rows"></code-line> }
<code-line class="line-numbers-rows"></code-line> created() {
<code-line class="line-numbers-rows"></code-line> // 获取验证码
<code-line class="line-numbers-rows"></code-line> this.getCode()
<code-line class="line-numbers-rows"></code-line> },
<code-line class="line-numbers-rows"></code-line> 

9689a3a555be58d6115e06f0de3dc695 - 前后端分离,SpringBoot如何实现验证码操作

__EOF__

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtNjiM65-1652720986379)(https://blog.csdn.net/alanlin/p/16276914.html)]北根娃 本文链接:https://blog.csdn.net/alanlin/p/16276914.html关于博主:评论和私信会在第一时间回复。或者直接私信我。版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

转载请注明:虚坏叔叔 » 前后端分离,SpringBoot如何实现验证码操作

喜欢 (0)

您必须 登录 才能发表评论!