Commit ec378d75de5660d873514fa16cfabb3671b9eeb4

Authored by YunaiV
1 parent e03a1a8b

v3.7.0 参数管理支持配置验证码开关

yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java
1 1 package cn.iocoder.yudao.framework.common.util.validation;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.util.StrUtil;
4 5 import org.springframework.util.StringUtils;
5 6  
  7 +import javax.validation.ConstraintViolation;
  8 +import javax.validation.ConstraintViolationException;
  9 +import javax.validation.Validator;
  10 +import java.util.Set;
6 11 import java.util.regex.Pattern;
7 12  
8 13 /**
... ... @@ -34,4 +39,11 @@ public class ValidationUtils {
34 39 && PATTERN_XML_NCNAME.matcher(str).matches();
35 40 }
36 41  
  42 + public static void validate(Validator validator, Object reqVO, Class<?>... groups) {
  43 + Set<ConstraintViolation<Object>> constraintViolations = validator.validate(reqVO, groups);
  44 + if (CollUtil.isNotEmpty(constraintViolations)) {
  45 + throw new ConstraintViolationException(constraintViolations);
  46 + }
  47 + }
  48 +
37 49 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java
... ... @@ -27,6 +27,7 @@ public interface PayClientConfig {
27 27 */
28 28 Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator);
29 29  
  30 + // TODO @aquan:貌似抽象一个 validation group 就好了!
30 31 /**
31 32 * 参数校验
32 33 *
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
... ... @@ -10,6 +10,16 @@ tenant-id: {{adminTenentId}}
10 10 "code": "1024"
11 11 }
12 12  
  13 +### 请求 /login 接口 => 成功(无验证码)
  14 +POST {{baseUrl}}/system/login
  15 +Content-Type: application/json
  16 +tenant-id: {{adminTenentId}}
  17 +
  18 +{
  19 + "username": "admin",
  20 + "password": "admin123"
  21 +}
  22 +
13 23 ### 请求 /get-permission-info 接口 => 成功
14 24 GET {{baseUrl}}/system/get-permission-info
15 25 Authorization: Bearer {{token}}
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginReqVO.java
... ... @@ -29,12 +29,17 @@ public class AuthLoginReqVO {
29 29 @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
30 30 private String password;
31 31  
32   - @ApiModelProperty(value = "验证码", required = true, example = "1024")
33   - @NotEmpty(message = "验证码不能为空")
  32 + @ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递")
  33 + @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
34 34 private String code;
35 35  
36   - @ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
37   - @NotEmpty(message = "唯一标识不能为空")
  36 + @ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62", notes = "验证码开启时,需要传递")
  37 + @NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class)
38 38 private String uuid;
39 39  
  40 + /**
  41 + * 开启验证码的 Group
  42 + */
  43 + public interface CodeEnableGroup {}
  44 +
40 45 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/common/vo/CaptchaImageRespVO.java
... ... @@ -14,11 +14,14 @@ import lombok.NoArgsConstructor;
14 14 @AllArgsConstructor
15 15 public class CaptchaImageRespVO {
16 16  
17   - @ApiModelProperty(value = "uuid", required = true, example = "1b3b7d00-83a8-4638-9e37-d67011855968",
18   - notes = "通过该 uuid 作为该验证码的标识")
  17 + @ApiModelProperty(value = "是否开启", required = true, example = "true", notes = "如果为 false,则关闭验证码功能")
  18 + private Boolean enable;
  19 +
  20 + @ApiModelProperty(value = "uuid", example = "1b3b7d00-83a8-4638-9e37-d67011855968",
  21 + notes = "enable = true 时,非空!通过该 uuid 作为该验证码的标识")
19 22 private String uuid;
20 23  
21   - @ApiModelProperty(value = "图片", required = true, notes = "验证码的图片内容,使用 Base64 编码")
  24 + @ApiModelProperty(value = "图片", notes = "enable = true 时,非空!验证码的图片内容,使用 Base64 编码")
22 25 private String img;
23 26  
24 27 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
... ... @@ -4,8 +4,10 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 5 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
6 6 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
  7 +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
7 8 import cn.iocoder.yudao.framework.security.core.LoginUser;
8 9 import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken;
  10 +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
9 11 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthLoginReqVO;
10 12 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialBindReqVO;
11 13 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLogin2ReqVO;
... ... @@ -16,7 +18,6 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
16 18 import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
17 19 import cn.iocoder.yudao.module.system.service.common.CaptchaService;
18 20 import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
19   -import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
20 21 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
21 22 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
22 23 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
... ... @@ -35,6 +36,7 @@ import org.springframework.stereotype.Service;
35 36 import org.springframework.util.Assert;
36 37  
37 38 import javax.annotation.Resource;
  39 +import javax.validation.Validator;
38 40 import java.util.Objects;
39 41 import java.util.Set;
40 42  
... ... @@ -69,6 +71,9 @@ public class AdminAuthServiceImpl implements AdminAuthService {
69 71 @Resource
70 72 private SocialUserService socialUserService;
71 73  
  74 + @Resource
  75 + private Validator validator;
  76 +
72 77 @Override
73 78 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
74 79 // 获取 username 对应的 AdminUserDO
... ... @@ -96,7 +101,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
96 101 @Override
97 102 public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) {
98 103 // 判断验证码是否正确
99   - this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode());
  104 + this.verifyCaptcha(reqVO);
100 105  
101 106 // 使用账号密码,进行登录
102 107 LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
... ... @@ -105,27 +110,29 @@ public class AdminAuthServiceImpl implements AdminAuthService {
105 110 return userSessionService.createUserSession(loginUser, userIp, userAgent);
106 111 }
107 112  
108   - private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
  113 + private void verifyCaptcha(AuthLoginReqVO reqVO) {
109 114 // 如果验证码关闭,则不进行校验
110 115 if (!captchaService.isCaptchaEnable()) {
111 116 return;
112 117 }
  118 + // 校验验证码
  119 + ValidationUtils.validate(validator, reqVO, AuthLoginReqVO.CodeEnableGroup.class);
113 120 // 验证码不存在
114 121 final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
115   - String code = captchaService.getCaptchaCode(captchaUUID);
  122 + String code = captchaService.getCaptchaCode(reqVO.getUuid());
116 123 if (code == null) {
117 124 // 创建登录失败日志(验证码不存在)
118   - this.createLoginLog(username, logTypeEnum, LoginResultEnum.CAPTCHA_NOT_FOUND);
  125 + this.createLoginLog(reqVO.getUsername(), logTypeEnum, LoginResultEnum.CAPTCHA_NOT_FOUND);
119 126 throw exception(AUTH_LOGIN_CAPTCHA_NOT_FOUND);
120 127 }
121 128 // 验证码不正确
122   - if (!code.equals(captchaCode)) {
  129 + if (!code.equals(reqVO.getCode())) {
123 130 // 创建登录失败日志(验证码不正确)
124   - this.createLoginLog(username, logTypeEnum, LoginResultEnum.CAPTCHA_CODE_ERROR);
  131 + this.createLoginLog(reqVO.getUsername(), logTypeEnum, LoginResultEnum.CAPTCHA_CODE_ERROR);
125 132 throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
126 133 }
127 134 // 正确,所以要删除下验证码
128   - captchaService.deleteCaptchaCode(captchaUUID);
  135 + captchaService.deleteCaptchaCode(reqVO.getUuid());
129 136 }
130 137  
131 138 private LoginUser login0(String username, String password) {
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/common/CaptchaServiceImpl.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.system.convert.common.CaptchaConvert;
7 7 import cn.iocoder.yudao.module.system.framework.captcha.config.CaptchaProperties;
8 8 import cn.iocoder.yudao.module.system.controller.admin.common.vo.CaptchaImageRespVO;
9 9 import cn.iocoder.yudao.module.system.dal.redis.common.CaptchaRedisDAO;
  10 +import org.springframework.beans.factory.annotation.Value;
10 11 import org.springframework.stereotype.Service;
11 12  
12 13 import javax.annotation.Resource;
... ... @@ -20,23 +21,35 @@ public class CaptchaServiceImpl implements CaptchaService {
20 21 @Resource
21 22 private CaptchaProperties captchaProperties;
22 23  
  24 + /**
  25 + * 验证码是否开关
  26 + *
  27 + * 虽然 {@link CaptchaProperties#getEnable()} 有该属性,但是 Apollo 在 Spring Boot 下无法刷新 @ConfigurationProperties 注解,
  28 + * 所以暂时只能这么处理~
  29 + */
  30 + @Value("${yudao.captcha.enable}")
  31 + private Boolean enable;
  32 +
23 33 @Resource
24 34 private CaptchaRedisDAO captchaRedisDAO;
25 35  
26 36 @Override
27 37 public CaptchaImageRespVO getCaptchaImage() {
  38 + if (!Boolean.TRUE.equals(enable)) {
  39 + return CaptchaImageRespVO.builder().enable(enable).build();
  40 + }
28 41 // 生成验证码
29 42 CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
30 43 // 缓存到 Redis 中
31 44 String uuid = IdUtil.fastSimpleUUID();
32 45 captchaRedisDAO.set(uuid, captcha.getCode(), captchaProperties.getTimeout());
33 46 // 返回
34   - return CaptchaConvert.INSTANCE.convert(uuid, captcha);
  47 + return CaptchaConvert.INSTANCE.convert(uuid, captcha).setEnable(enable);
35 48 }
36 49  
37 50 @Override
38 51 public Boolean isCaptchaEnable() {
39   - return captchaProperties.getEnable();
  52 + return enable;
40 53 }
41 54  
42 55 @Override
... ...
yudao-ui-admin/src/views/login.vue
... ... @@ -17,7 +17,7 @@
17 17 <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
18 18 </el-input>
19 19 </el-form-item>
20   - <el-form-item prop="code">
  20 + <el-form-item prop="code" v-if="captchaEnable">
21 21 <el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin">
22 22 <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
23 23 </el-input>
... ... @@ -61,6 +61,7 @@ export default {
61 61 data() {
62 62 return {
63 63 codeUrl: "",
  64 + captchaEnable: true,
64 65 loginForm: {
65 66 username: "admin",
66 67 password: "admin123",
... ... @@ -119,10 +120,18 @@ export default {
119 120 },
120 121 methods: {
121 122 getCode() {
  123 + // 只有开启的状态,才加载验证码。默认开启
  124 + if (!this.captchaEnable) {
  125 + return;
  126 + }
  127 + // 请求远程,获得验证码
122 128 getCodeImg().then(res => {
123 129 res = res.data;
124   - this.codeUrl = "data:image/gif;base64," + res.img;
125   - this.loginForm.uuid = res.uuid;
  130 + this.captchaEnable = res.enable;
  131 + if (this.captchaEnable) {
  132 + this.codeUrl = "data:image/gif;base64," + res.img;
  133 + this.loginForm.uuid = res.uuid;
  134 + }
126 135 });
127 136 },
128 137 getCookie() {
... ...
更新日志.md
... ... @@ -37,6 +37,7 @@
37 37 * 【新增】前端的网页标题支持根据选择的菜单,动态展示标题 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/7bf9a85263e0c44b2bc88485b83557c129583f5c)
38 38 * 【新增】字典标签样式回显,例如说开启的状态展示为 primary 蓝色,禁用的状态为 info 灰色 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/986d1328e0a0d37e2de2fb9d937faeed9d9bee7b)
39 39 * 【新增】前端的 iframe 组件,方便内嵌网页 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/4a8129bffa9e3928c56333e29f5874f55a079764)
  40 +* 【新增】在基础设施-配置管理菜单,可通过修改 `yudao.captcha.enable` 配置项,动态修改登录是否需要验证码 [commit]()
40 41  
41 42 ### 🐞 Bug Fixes
42 43  
... ...