Browse Source

增加图片验证码接口

YunaiV 4 years ago
parent
commit
e85c342696
18 changed files with 331 additions and 11 deletions
  1. 27 6
      pom.xml
  2. 9 0
      src/main/java/cn/iocoder/dashboard/framework/captcha/config/CaptchaConfig.java
  3. 31 0
      src/main/java/cn/iocoder/dashboard/framework/captcha/config/CaptchaProperties.java
  4. 4 0
      src/main/java/cn/iocoder/dashboard/framework/captcha/package-info.java
  5. 2 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.http
  6. 30 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.java
  7. 23 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/common/vo/SysCaptchaImageRespVO.java
  8. 18 0
      src/main/java/cn/iocoder/dashboard/modules/system/convert/common/SysCaptchaConvert.java
  9. 6 0
      src/main/java/cn/iocoder/dashboard/modules/system/convert/package-info.java
  10. 1 0
      src/main/java/cn/iocoder/dashboard/modules/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md
  11. 32 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java
  12. 0 4
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyContants.java
  13. 42 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java
  14. 44 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/common/SysCaptchaRedisDAO.java
  15. 4 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/package-info.java
  16. 12 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaService.java
  17. 38 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/common/impl/SysCaptchaServiceImpl.java
  18. 8 1
      src/main/resources/application.yaml

+ 27 - 6
pom.xml

@@ -49,8 +49,8 @@
         <mybatis-plus.version>3.4.1</mybatis-plus.version>
         <redisson.version>3.13.6</redisson.version>
         <!-- 工具类相关 -->
-        <org.projectlombok.version>1.16.14</org.projectlombok.version>
-        <org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
+        <lombok.version>1.16.14</lombok.version>
+        <mapstruct.version>1.4.1.Final</mapstruct.version>
         <jjwt.version>0.9.1</jjwt.version>
         <fastjson.version>1.2.75</fastjson.version>
         <hutool.version>5.5.6</hutool.version>
@@ -252,7 +252,7 @@
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
-            <version>${org.projectlombok.version}</version>
+            <version>${lombok.version}</version>
         </dependency>
 
         <dependency>
@@ -270,7 +270,7 @@
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
-            <version>${org.projectlombok.version}</version>
+            <version>${lombok.version}</version>
         </dependency>
 
         <dependency>
@@ -280,11 +280,32 @@
             <version>1.21</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
+            <version>${mapstruct.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-jdk8</artifactId>
+            <version>${mapstruct.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-core</artifactId>
             <version>${hutool.version}</version>
         </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-extra</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-captcha</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
     </dependencies>
 
 
@@ -303,12 +324,12 @@
                             <path>
                                 <groupId>org.mapstruct</groupId>
                                 <artifactId>mapstruct-processor</artifactId>
-                                <version>${org.mapstruct.version}</version>
+                                <version>${mapstruct.version}</version>
                             </path>
                             <path>
                                 <groupId>org.projectlombok</groupId>
                                 <artifactId>lombok</artifactId>
-                                <version>${org.projectlombok.version}</version>
+                                <version>${lombok.version}</version>
                             </path>
                         </annotationProcessorPaths>
                     </configuration>

+ 9 - 0
src/main/java/cn/iocoder/dashboard/framework/captcha/config/CaptchaConfig.java

@@ -0,0 +1,9 @@
+package cn.iocoder.dashboard.framework.captcha.config;
+
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties(CaptchaProperties.class)
+public class CaptchaConfig {
+}

+ 31 - 0
src/main/java/cn/iocoder/dashboard/framework/captcha/config/CaptchaProperties.java

@@ -0,0 +1,31 @@
+package cn.iocoder.dashboard.framework.captcha.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.NotNull;
+import java.time.Duration;
+
+@ConfigurationProperties(prefix = "yudao.captcha")
+@Validated
+@Data
+public class CaptchaProperties {
+
+    /**
+     * 验证码的过期时间
+     */
+    @NotNull(message = "验证码的过期时间不为空")
+    private Duration timeout;
+    /**
+     * 验证码的高度
+     */
+    @NotNull(message = "验证码的高度不能为空")
+    private Integer height;
+    /**
+     * 验证码的宽度
+     */
+    @NotNull(message = "验证码的宽度不能为空")
+    private Integer width;
+
+}

+ 4 - 0
src/main/java/cn/iocoder/dashboard/framework/captcha/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 基于 Hutool captcha 库,实现验证码功能
+ */
+package cn.iocoder.dashboard.framework.captcha;

+ 2 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.http

@@ -0,0 +1,2 @@
+### 请求 /captcha/get-image 接口 => 成功
+GET {{baseUrl}}/captcha/get-image

+ 30 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.java

@@ -0,0 +1,30 @@
+package cn.iocoder.dashboard.modules.system.controller.common;
+
+import cn.iocoder.dashboard.common.pojo.CommonResult;
+import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageRespVO;
+import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
+
+@Api(tags = "验证码 API")
+@RestController
+@RequestMapping("/captcha")
+public class SysCaptchaController {
+
+    @Resource
+    private SysCaptchaService captchaService;
+
+    @ApiOperation("生成图片验证码")
+    @GetMapping("/get-image")
+    private CommonResult<SysCaptchaImageRespVO> getCaptchaImage() {
+        return success(captchaService.getCaptchaImage());
+    }
+
+}

+ 23 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/vo/SysCaptchaImageRespVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.dashboard.modules.system.controller.common.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@ApiModel("验证码图片 Response VO")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SysCaptchaImageRespVO {
+
+    @ApiModelProperty(value = "uuid", required = true, example = "1b3b7d00-83a8-4638-9e37-d67011855968", notes = "通过该 uuid 作为该验证码的标识")
+    private String uuid;
+
+    @ApiModelProperty(value = "图片", required = true, notes = "验证码的图片内容,使用 Base64 编码")
+    private String img;
+
+}

+ 18 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/common/SysCaptchaConvert.java

@@ -0,0 +1,18 @@
+package cn.iocoder.dashboard.modules.system.convert.common;
+
+import cn.hutool.captcha.AbstractCaptcha;
+import cn.hutool.captcha.ICaptcha;
+import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageRespVO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public interface SysCaptchaConvert {
+
+    SysCaptchaConvert INSTANCE = Mappers.getMapper(SysCaptchaConvert.class);
+
+    default SysCaptchaImageRespVO convert(String uuid, AbstractCaptcha captcha) {
+        return SysCaptchaImageRespVO.builder().uuid(uuid).img(captcha.getImageBase64()).build();
+    }
+
+}

+ 6 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/package-info.java

@@ -0,0 +1,6 @@
+/**
+ * 提供 POJO 类的实体转换
+ *
+ * 目前使用 MapStruct 框架
+ */
+package cn.iocoder.dashboard.modules.system.convert;

+ 1 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md

@@ -0,0 +1 @@
+<http://www.iocoder.cn/Spring-Boot/MapStruct/?dashboard>

+ 32 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java

@@ -0,0 +1,32 @@
+package cn.iocoder.dashboard.modules.system.dal.redis;
+
+import cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine;
+import cn.iocoder.dashboard.framework.security.core.LoginUser;
+
+import java.time.Duration;
+
+import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
+import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.TIMEOUT_DYNAMIC;
+
+/**
+ * Redis Key 枚举类
+ *
+ * @author 芋道源码
+ */
+public interface RedisKeyConstants {
+
+    /**
+     * {@link LoginUser} 的缓存
+     *
+     * key 的 format 的参数是 sessionId
+     */
+    RedisKeyDefine LOGIN_USER = new RedisKeyDefine("login_user:%s", STRING, LoginUser.class, Duration.ofMinutes(30));
+
+    /**
+     * 验证码的缓存
+     *
+     * key 的 format 的参数是 uuid
+     */
+    RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("captcha_code:%s", STRING, String.class, TIMEOUT_DYNAMIC);
+
+}

+ 0 - 4
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyContants.java

@@ -1,4 +0,0 @@
-package cn.iocoder.dashboard.modules.system.dal.redis;
-
-public class RedisKeyContants {
-}

+ 42 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/auth/SysLoginUserRedisDAO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.dashboard.modules.system.dal.redis.dao.auth;
+
+import cn.iocoder.dashboard.framework.security.core.LoginUser;
+import com.alibaba.fastjson.JSON;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.dashboard.modules.system.dal.redis.RedisKeyConstants.LOGIN_USER;
+
+/**
+ * {@link LoginUser} 的 RedisDAO
+ *
+ * @author 芋道源码
+ */
+@Repository
+public class SysLoginUserRedisDAO {
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    public LoginUser get(String sessionId) {
+        String redisKey = formatKey(sessionId);
+        return JSON.parseObject(stringRedisTemplate.opsForValue().get(redisKey), LoginUser.class);
+    }
+
+    public void set(String sessionId, LoginUser loginUser) {
+        String redisKey = formatKey(sessionId);
+        stringRedisTemplate.opsForValue().set(redisKey, JSON.toJSONString(loginUser), LOGIN_USER.getTimeout());
+    }
+
+    public void delete(String accessToken) {
+        String redisKey = formatKey(accessToken);
+        stringRedisTemplate.delete(redisKey);
+    }
+
+    private static String formatKey(String sessionId) {
+        return String.format(LOGIN_USER.getKeyTemplate(), sessionId);
+    }
+
+}

+ 44 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/common/SysCaptchaRedisDAO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.dashboard.modules.system.dal.redis.dao.common;
+
+import cn.iocoder.dashboard.framework.security.core.LoginUser;
+import com.alibaba.fastjson.JSON;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+
+import java.time.Duration;
+
+import static cn.iocoder.dashboard.modules.system.dal.redis.RedisKeyConstants.CAPTCHA_CODE;
+
+/**
+ * 验证码的 Redis DAO
+ *
+ * @author 芋道源码
+ */
+@Repository
+public class SysCaptchaRedisDAO {
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    public String get(String uuid) {
+        String redisKey = formatKey(uuid);
+        return stringRedisTemplate.opsForValue().get(redisKey);
+    }
+
+    public void set(String uuid, String code, Duration timeout) {
+        String redisKey = formatKey(uuid);
+        stringRedisTemplate.opsForValue().set(redisKey, code, timeout);
+    }
+
+    public void delete(String uuid) {
+        String redisKey = formatKey(uuid);
+        stringRedisTemplate.delete(redisKey);
+    }
+
+    private static String formatKey(String uuid) {
+        return String.format(CAPTCHA_CODE.getKeyTemplate(), uuid);
+    }
+
+}

+ 4 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/dao/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 提供 Redis 访问的 DAO
+ */
+package cn.iocoder.dashboard.modules.system.dal.redis.dao;

+ 12 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaService.java

@@ -0,0 +1,12 @@
+package cn.iocoder.dashboard.modules.system.service.common;
+
+import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageRespVO;
+
+/**
+ * 验证码 Service 接口
+ */
+public interface SysCaptchaService {
+
+    SysCaptchaImageRespVO getCaptchaImage();
+
+}

+ 38 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/common/impl/SysCaptchaServiceImpl.java

@@ -0,0 +1,38 @@
+package cn.iocoder.dashboard.modules.system.service.common.impl;
+
+import cn.hutool.captcha.CaptchaUtil;
+import cn.hutool.captcha.CircleCaptcha;
+import cn.hutool.core.util.IdUtil;
+import cn.iocoder.dashboard.framework.captcha.config.CaptchaProperties;
+import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageRespVO;
+import cn.iocoder.dashboard.modules.system.convert.common.SysCaptchaConvert;
+import cn.iocoder.dashboard.modules.system.dal.redis.dao.common.SysCaptchaRedisDAO;
+import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 验证码 Service 实现类
+ */
+@Service
+public class SysCaptchaServiceImpl implements SysCaptchaService {
+
+    @Resource
+    private CaptchaProperties captchaProperties;
+
+    @Resource
+    private SysCaptchaRedisDAO captchaRedisDAO;
+
+    @Override
+    public SysCaptchaImageRespVO getCaptchaImage() {
+        // 生成验证码
+        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
+        // 缓存到 Redis 中
+        String uuid = IdUtil.fastSimpleUUID();
+        captchaRedisDAO.set(uuid, captcha.getCode(), captchaProperties.getTimeout());
+        // 返回
+        return SysCaptchaConvert.INSTANCE.convert(uuid, captcha);
+    }
+
+}

+ 8 - 1
src/main/resources/application.yaml

@@ -1,4 +1,6 @@
 spring:
+  application:
+    name: dashboard
   # 数据源配置项 TODO 多数据源;TODO 监控配置
   datasource:
     url: jdbc:mysql://127.0.1:3306/ruoyi-vue-pro?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
@@ -21,9 +23,14 @@ yudao:
   security:
     token-header: Authorization
     token-secret: abcdefghijklmnopqrstuvwxyz
-    token-expires: 30m
+    token-timeout: 1d
+    session-timeout: 30m
   swagger:
     title: 管理后台
     description: 提供管理员管理的所有功能
     version: 1.0.0
     base-package: cn.iocoder.dashboard.modules
+  captcha:
+    timeout: 5m
+    width: 160
+    height: 60