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

560阅读 0评论2022-05-24 fhadmin
分类:Java


点击(此处)折叠或打开



  1. 1|0SpringBoot 版本
  2. 本文基于的 Spring Boot 的版本是 2.6.7 。

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

  5. <!--验证码-->
  6. <dependency>
  7.     <groupId>com.github.whvcse</groupId>
  8.     <artifactId>easy-captcha</artifactId>
  9.     <version>1.6.2</version>
  10. </dependency>
  11. 把生成的验证码结果保存到 redis 缓存中,并设置过期时间。
  12. 前端通过提交验证码和 key,其中 key 就是保存到 redis 中的键,通过这个键获取到对应的值,再与前端提交的值对比,相同就通过验证。
  13. 3|1 实现过程
  14. 新建验证码枚举类
  15. 由于 captcha 这款验证码提供了好几种验证码方法,有中文验证码,动态验证码,算术验证码等等,新建一个验证码每周类存放这几种验证码类型。代码如下:

  16. // fhadmin.cn
  17. public enum LoginCodeEnum {
  18.     /**
  19.      * 算数
  20.      */
  21.     ARITHMETIC,
  22.     /**
  23.      * 中文
  24.      */
  25.     CHINESE,
  26.     /**
  27.      * 中文闪图
  28.      */
  29.     CHINESE_GIF,
  30.     /**
  31.      * 闪图
  32.      */
  33.     GIF,
  34.     SPEC
  35. }
  36. 该类是定义验证码的基本信息,例如高度、宽度、字体类型、验证码类型等等、并且我们把它转成通过 SpringBoot 配置文件类型来定义更加方便。

  37. // fhadmin.cn
  38. @Data
  39. public class LoginCode {

  40.     /**
  41.      * 验证码配置
  42.      */
  43.     private LoginCodeEnum codeType;
  44.     /**
  45.      * 验证码有效期 分钟
  46.      */
  47.     private Long expiration = 2L;
  48.     /**
  49.      * 验证码内容长度
  50.      */
  51.     private int length = 2;
  52.     /**
  53.      * 验证码宽度
  54.      */
  55.     private int width = 111;
  56.     /**
  57.      * 验证码高度
  58.      */
  59.     private int height = 36;
  60.     /**
  61.      * 验证码字体
  62.      */
  63.     private String fontName;
  64.     /**
  65.      * 字体大小
  66.      */
  67.     private int fontSize = 25;

  68.     /**
  69.      * 验证码前缀
  70.      * @return
  71.      */
  72.     private String codeKey;


  73.     public LoginCodeEnum getCodeType() {
  74.         return codeType;
  75.     }
  76. }
  77. 把配置文件转换 Pojo 类的统一配置类

  78. // fhadmin.cn
  79. @Configuration
  80. public class ConfigBeanConfiguration {

  81.     @Bean
  82.     @ConfigurationProperties(prefix = "login")
  83.     public LoginProperties loginProperties() {
  84.         return new LoginProperties();
  85.     }
  86. }
  87. 定义逻辑验证生成类

  88. // fhadmin.cn
  89. @Data
  90. public class LoginProperties {

  91.     private LoginCode loginCode;


  92.     /**
  93.      * 获取验证码生产类
  94.      * @return
  95.      */
  96.     public Captcha getCaptcha(){
  97.         if(Objects.isNull(loginCode)){
  98.             loginCode = new LoginCode();
  99.             if(Objects.isNull(loginCode.getCodeType())){
  100.                 loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
  101.             }

  102.         }
  103.         return switchCaptcha(loginCode);
  104.     }

  105.     /**
  106.      * 依据配置信息生产验证码
  107.      * @param loginCode
  108.      * @return
  109.      */
  110.     private Captcha switchCaptcha(LoginCode loginCode){
  111.         Captcha captcha = null;
  112.         synchronized (this){
  113.             switch (loginCode.getCodeType()){
  114.                 case ARITHMETIC:
  115.                     captcha = new FixedArithmeticCaptcha(loginCode.getWidth(),loginCode.getHeight());
  116.                     captcha.setLen(loginCode.getLength());
  117.                     break;
  118.                 case CHINESE:
  119.                     captcha = new ChineseCaptcha(loginCode.getWidth(),loginCode.getHeight());
  120.                     captcha.setLen(loginCode.getLength());
  121.                     break;
  122.                 case CHINESE_GIF:
  123.                     captcha = new ChineseGifCaptcha(loginCode.getWidth(),loginCode.getHeight());
  124.                     captcha.setLen(loginCode.getLength());
  125.                     break;
  126.                 case GIF:
  127.                     captcha = new GifCaptcha(loginCode.getWidth(),loginCode.getHeight());
  128.                     captcha.setLen(loginCode.getLength());
  129.                     break;
  130.                 case SPEC:
  131.                     captcha = new SpecCaptcha(loginCode.getWidth(),loginCode.getHeight());
  132.                     captcha.setLen(loginCode.getLength());
  133.                 default:
  134.                     System.out.println("验证码配置信息错误!正确配置查看 LoginCodeEnum ");

  135.             }
  136.         }
  137.         if(StringUtils.isNotBlank(loginCode.getFontName())){
  138.             captcha.setFont(new Font(loginCode.getFontName(),Font.PLAIN,loginCode.getFontSize()));
  139.         }
  140.         return captcha;
  141.     }

  142.     static class FixedArithmeticCaptcha extends ArithmeticCaptcha{
  143.         public FixedArithmeticCaptcha(int width,int height){
  144.             super(width,height);
  145.         }

  146.         @Override
  147.         protected char[] alphas() {
  148.             // 生成随机数字和运算符
  149.             int n1 = num(1, 10), n2 = num(1, 10);
  150.             int opt = num(3);

  151.             // 计算结果
  152.             int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
  153.             // 转换为字符运算符
  154.             char optChar = "+-x".charAt(opt);

  155.             this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
  156.             this.chars = String.valueOf(res);

  157.             return chars.toCharArray();
  158.         }
  159.     }
  160. }

  161. 控制层定义验证生成接口

  162. // fhadmin.cn
  163. @ApiOperation(value = "获取验证码", notes = "获取验证码")
  164.     @GetMapping("/code")
  165.     public Object getCode(){

  166.         Captcha captcha = loginProperties.getCaptcha();
  167.         String uuid = "code-key-"+IdUtil.simpleUUID();
  168.         //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型
  169.         String captchaValue = captcha.text();
  170.         if(captcha.getCharType()-1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")){
  171.             captchaValue = captchaValue.split("\\.")[0];
  172.         }
  173.         // 保存
  174.         redisUtils.set(uuid,captchaValue,loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
  175.         // 验证码信息
  176.         Map<String,Object> imgResult = new HashMap<String,Object>(2){{
  177.             put("img",captcha.toBase64());
  178.             put("uuid",uuid);
  179.         }};
  180.         return imgResult;

  181.     }
  182. 前端调用接口

  183. <template>
  184. <div class="login-code">
  185.   <img :src="codeUrl" @click="getCode">
  186. </div>
  187. </template>
  188. <script>
  189.     methods: {
  190.     getCode() {
  191.       getCodeImg().then(res => {
  192.         this.codeUrl = res.data.img
  193.         this.loginForm.uuid = res.data.uuid
  194.       })
  195.     },
  196.     }
  197.     created() {
  198.     // 获取验证码
  199.     this.getCode()
  200.   },
  201.  </script>



点击(此处)折叠或打开



  1. 1|0SpringBoot 版本
  2. 本文基于的 Spring Boot 的版本是 2.6.7 。

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

  5. <!--验证码-->
  6. <dependency>
  7.     <groupId>com.github.whvcse</groupId>
  8.     <artifactId>easy-captcha</artifactId>
  9.     <version>1.6.2</version>
  10. </dependency>
  11. 把生成的验证码结果保存到 redis 缓存中,并设置过期时间。
  12. 前端通过提交验证码和 key,其中 key 就是保存到 redis 中的键,通过这个键获取到对应的值,再与前端提交的值对比,相同就通过验证。
  13. 3|1 实现过程
  14. 新建验证码枚举类
  15. 由于 captcha 这款验证码提供了好几种验证码方法,有中文验证码,动态验证码,算术验证码等等,新建一个验证码每周类存放这几种验证码类型。代码如下:

  16. // fhadmin.cn
  17. public enum LoginCodeEnum {
  18.     /**
  19.      * 算数
  20.      */
  21.     ARITHMETIC,
  22.     /**
  23.      * 中文
  24.      */
  25.     CHINESE,
  26.     /**
  27.      * 中文闪图
  28.      */
  29.     CHINESE_GIF,
  30.     /**
  31.      * 闪图
  32.      */
  33.     GIF,
  34.     SPEC
  35. }
  36. 该类是定义验证码的基本信息,例如高度、宽度、字体类型、验证码类型等等、并且我们把它转成通过 SpringBoot 配置文件类型来定义更加方便。

  37. // fhadmin.cn
  38. @Data
  39. public class LoginCode {

  40.     /**
  41.      * 验证码配置
  42.      */
  43.     private LoginCodeEnum codeType;
  44.     /**
  45.      * 验证码有效期 分钟
  46.      */
  47.     private Long expiration = 2L;
  48.     /**
  49.      * 验证码内容长度
  50.      */
  51.     private int length = 2;
  52.     /**
  53.      * 验证码宽度
  54.      */
  55.     private int width = 111;
  56.     /**
  57.      * 验证码高度
  58.      */
  59.     private int height = 36;
  60.     /**
  61.      * 验证码字体
  62.      */
  63.     private String fontName;
  64.     /**
  65.      * 字体大小
  66.      */
  67.     private int fontSize = 25;

  68.     /**
  69.      * 验证码前缀
  70.      * @return
  71.      */
  72.     private String codeKey;


  73.     public LoginCodeEnum getCodeType() {
  74.         return codeType;
  75.     }
  76. }
  77. 把配置文件转换 Pojo 类的统一配置类

  78. // fhadmin.cn
  79. @Configuration
  80. public class ConfigBeanConfiguration {

  81.     @Bean
  82.     @ConfigurationProperties(prefix = "login")
  83.     public LoginProperties loginProperties() {
  84.         return new LoginProperties();
  85.     }
  86. }
  87. 定义逻辑验证生成类

  88. // fhadmin.cn
  89. @Data
  90. public class LoginProperties {

  91.     private LoginCode loginCode;


  92.     /**
  93.      * 获取验证码生产类
  94.      * @return
  95.      */
  96.     public Captcha getCaptcha(){
  97.         if(Objects.isNull(loginCode)){
  98.             loginCode = new LoginCode();
  99.             if(Objects.isNull(loginCode.getCodeType())){
  100.                 loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
  101.             }

  102.         }
  103.         return switchCaptcha(loginCode);
  104.     }

  105.     /**
  106.      * 依据配置信息生产验证码
  107.      * @param loginCode
  108.      * @return
  109.      */
  110.     private Captcha switchCaptcha(LoginCode loginCode){
  111.         Captcha captcha = null;
  112.         synchronized (this){
  113.             switch (loginCode.getCodeType()){
  114.                 case ARITHMETIC:
  115.                     captcha = new FixedArithmeticCaptcha(loginCode.getWidth(),loginCode.getHeight());
  116.                     captcha.setLen(loginCode.getLength());
  117.                     break;
  118.                 case CHINESE:
  119.                     captcha = new ChineseCaptcha(loginCode.getWidth(),loginCode.getHeight());
  120.                     captcha.setLen(loginCode.getLength());
  121.                     break;
  122.                 case CHINESE_GIF:
  123.                     captcha = new ChineseGifCaptcha(loginCode.getWidth(),loginCode.getHeight());
  124.                     captcha.setLen(loginCode.getLength());
  125.                     break;
  126.                 case GIF:
  127.                     captcha = new GifCaptcha(loginCode.getWidth(),loginCode.getHeight());
  128.                     captcha.setLen(loginCode.getLength());
  129.                     break;
  130.                 case SPEC:
  131.                     captcha = new SpecCaptcha(loginCode.getWidth(),loginCode.getHeight());
  132.                     captcha.setLen(loginCode.getLength());
  133.                 default:
  134.                     System.out.println("验证码配置信息错误!正确配置查看 LoginCodeEnum ");

  135.             }
  136.         }
  137.         if(StringUtils.isNotBlank(loginCode.getFontName())){
  138.             captcha.setFont(new Font(loginCode.getFontName(),Font.PLAIN,loginCode.getFontSize()));
  139.         }
  140.         return captcha;
  141.     }

  142.     static class FixedArithmeticCaptcha extends ArithmeticCaptcha{
  143.         public FixedArithmeticCaptcha(int width,int height){
  144.             super(width,height);
  145.         }

  146.         @Override
  147.         protected char[] alphas() {
  148.             // 生成随机数字和运算符
  149.             int n1 = num(1, 10), n2 = num(1, 10);
  150.             int opt = num(3);

  151.             // 计算结果
  152.             int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
  153.             // 转换为字符运算符
  154.             char optChar = "+-x".charAt(opt);

  155.             this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
  156.             this.chars = String.valueOf(res);

  157.             return chars.toCharArray();
  158.         }
  159.     }
  160. }

  161. 控制层定义验证生成接口

  162. // fhadmin.cn
  163. @ApiOperation(value = "获取验证码", notes = "获取验证码")
  164.     @GetMapping("/code")
  165.     public Object getCode(){

  166.         Captcha captcha = loginProperties.getCaptcha();
  167.         String uuid = "code-key-"+IdUtil.simpleUUID();
  168.         //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型
  169.         String captchaValue = captcha.text();
  170.         if(captcha.getCharType()-1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")){
  171.             captchaValue = captchaValue.split("\\.")[0];
  172.         }
  173.         // 保存
  174.         redisUtils.set(uuid,captchaValue,loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
  175.         // 验证码信息
  176.         Map<String,Object> imgResult = new HashMap<String,Object>(2){{
  177.             put("img",captcha.toBase64());
  178.             put("uuid",uuid);
  179.         }};
  180.         return imgResult;

  181.     }
  182. 前端调用接口

  183. <template>
  184. <div class="login-code">
  185.   <img :src="codeUrl" @click="getCode">
  186. </div>
  187. </template>
  188. <script>
  189.     methods: {
  190.     getCode() {
  191.       getCodeImg().then(res => {
  192.         this.codeUrl = res.data.img
  193.         this.loginForm.uuid = res.data.uuid
  194.       })
  195.     },
  196.     }
  197.     created() {
  198.     // 获取验证码
  199.     this.getCode()
  200.   },
  201.  </script>


上一篇:springcloud Alibaba 2021.0.1.0 springboot 2.7.0 整合 Swagger3.0 报错解决方案
下一篇:java 生成 zip格式 压缩文件