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