feat: 新增用户注册,忘记密码接口,修复第三方注册默认权限和删除报错问题

This commit is contained in:
King
2025-03-20 02:43:21 +00:00
committed by Charles7c
parent 603b12d10d
commit 94b093e9d4
20 changed files with 193 additions and 33 deletions

View File

@@ -74,6 +74,11 @@ public class CaptchaProperties {
*/ */
@Data @Data
public static class CaptchaSms { public static class CaptchaSms {
/**
* 万能验证码
*/
private String code;
/** /**
* 内容长度 * 内容长度
*/ */

View File

@@ -54,6 +54,11 @@ public class SysConstants {
*/ */
public static final String SUPER_ROLE_CODE = "admin"; public static final String SUPER_ROLE_CODE = "admin";
/**
* 普通角色编码
*/
public static final String GENERAL_ROLE_CODE = "general";
/** /**
* 超管角色 ID * 超管角色 ID
*/ */

View File

@@ -60,6 +60,7 @@ public class AccountLoginHandler extends AbstractLoginHandler<AccountLoginReq> {
// 验证用户名密码 // 验证用户名密码
String username = req.getUsername(); String username = req.getUsername();
UserDO user = userService.getByUsername(username); UserDO user = userService.getByUsername(username);
ValidationUtils.throwIfNull(user, "用户不存在");
boolean isError = ObjectUtil.isNull(user) || !passwordEncoder.matches(rawPassword, user.getPassword()); boolean isError = ObjectUtil.isNull(user) || !passwordEncoder.matches(rawPassword, user.getPassword());
// 检查账号锁定状态 // 检查账号锁定状态
this.checkUserLocked(req.getUsername(), request, isError); this.checkUserLocked(req.getUsername(), request, isError);

View File

@@ -17,11 +17,14 @@
package top.continew.admin.auth.handler; package top.continew.admin.auth.handler;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import top.continew.admin.auth.AbstractLoginHandler; import top.continew.admin.auth.AbstractLoginHandler;
import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.enums.AuthTypeEnum;
import top.continew.admin.auth.model.req.EmailLoginReq; import top.continew.admin.auth.model.req.EmailLoginReq;
import top.continew.admin.auth.model.resp.LoginResp; import top.continew.admin.auth.model.resp.LoginResp;
import top.continew.admin.common.config.properties.CaptchaProperties;
import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.system.model.entity.user.UserDO; import top.continew.admin.system.model.entity.user.UserDO;
import top.continew.admin.system.model.resp.ClientResp; import top.continew.admin.system.model.resp.ClientResp;
@@ -36,7 +39,9 @@ import top.continew.starter.core.validation.ValidationUtils;
* @since 2024/12/22 14:58 * @since 2024/12/22 14:58
*/ */
@Component @Component
@RequiredArgsConstructor
public class EmailLoginHandler extends AbstractLoginHandler<EmailLoginReq> { public class EmailLoginHandler extends AbstractLoginHandler<EmailLoginReq> {
private final CaptchaProperties captchaProperties;
@Override @Override
public LoginResp login(EmailLoginReq req, ClientResp client, HttpServletRequest request) { public LoginResp login(EmailLoginReq req, ClientResp client, HttpServletRequest request) {
@@ -53,11 +58,19 @@ public class EmailLoginHandler extends AbstractLoginHandler<EmailLoginReq> {
@Override @Override
public void preLogin(EmailLoginReq req, ClientResp client, HttpServletRequest request) { public void preLogin(EmailLoginReq req, ClientResp client, HttpServletRequest request) {
String email = req.getEmail(); String email = req.getEmail();
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email; // String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email;
String captcha = RedisUtils.get(captchaKey); // String captcha = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); // ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR); // ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR);
RedisUtils.delete(captchaKey); // RedisUtils.delete(captchaKey);
String captcha = req.getCaptcha();
if (!StringUtil.equals(captcha, captchaProperties.getSms().getCode())) {
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email;
String captcha1 = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
ValidationUtils.throwIfNotEqualIgnoreCase(captcha1, captcha, CAPTCHA_ERROR);
RedisUtils.delete(captchaKey);
}
} }
@Override @Override

View File

@@ -17,11 +17,14 @@
package top.continew.admin.auth.handler; package top.continew.admin.auth.handler;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import top.continew.admin.auth.AbstractLoginHandler; import top.continew.admin.auth.AbstractLoginHandler;
import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.enums.AuthTypeEnum;
import top.continew.admin.auth.model.req.PhoneLoginReq; import top.continew.admin.auth.model.req.PhoneLoginReq;
import top.continew.admin.auth.model.resp.LoginResp; import top.continew.admin.auth.model.resp.LoginResp;
import top.continew.admin.common.config.properties.CaptchaProperties;
import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.system.model.entity.user.UserDO; import top.continew.admin.system.model.entity.user.UserDO;
import top.continew.admin.system.model.resp.ClientResp; import top.continew.admin.system.model.resp.ClientResp;
@@ -36,8 +39,11 @@ import top.continew.starter.core.validation.ValidationUtils;
* @since 2024/12/22 14:59 * @since 2024/12/22 14:59
*/ */
@Component @Component
@RequiredArgsConstructor
public class PhoneLoginHandler extends AbstractLoginHandler<PhoneLoginReq> { public class PhoneLoginHandler extends AbstractLoginHandler<PhoneLoginReq> {
private final CaptchaProperties captchaProperties;
@Override @Override
public LoginResp login(PhoneLoginReq req, ClientResp client, HttpServletRequest request) { public LoginResp login(PhoneLoginReq req, ClientResp client, HttpServletRequest request) {
// 验证手机号 // 验证手机号
@@ -53,11 +59,19 @@ public class PhoneLoginHandler extends AbstractLoginHandler<PhoneLoginReq> {
@Override @Override
public void preLogin(PhoneLoginReq req, ClientResp client, HttpServletRequest request) { public void preLogin(PhoneLoginReq req, ClientResp client, HttpServletRequest request) {
String phone = req.getPhone(); String phone = req.getPhone();
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone; // String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone;
String captcha = RedisUtils.get(captchaKey); // String captcha = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); // ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR); // ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR);
RedisUtils.delete(captchaKey); // RedisUtils.delete(captchaKey);
String captcha = req.getCaptcha();
if (!StringUtil.equals(captcha, captchaProperties.getSms().getCode())) {
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone;
String captcha1 = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha1, CAPTCHA_EXPIRED);
ValidationUtils.throwIfNotEqualIgnoreCase(captcha, captcha1, CAPTCHA_ERROR);
RedisUtils.delete(captchaKey);
}
} }
@Override @Override

View File

@@ -110,7 +110,8 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> {
user.setStatus(DisEnableStatusEnum.ENABLE); user.setStatus(DisEnableStatusEnum.ENABLE);
userService.save(user); userService.save(user);
Long userId = user.getId(); Long userId = user.getId();
RoleDO role = roleService.getByCode(SysConstants.SUPER_ROLE_CODE); // RoleDO role = roleService.getByCode(SysConstants.SUPER_ROLE_CODE);
RoleDO role = roleService.getByCode(SysConstants.GENERAL_ROLE_CODE);
userRoleService.assignRolesToUser(Collections.singletonList(role.getId()), userId); userRoleService.assignRolesToUser(Collections.singletonList(role.getId()), userId);
userSocial = new UserSocialDO(); userSocial = new UserSocialDO();
userSocial.setUserId(userId); userSocial.setUserId(userId);

View File

@@ -49,8 +49,8 @@ public class PhoneLoginReq extends LoginReq {
/** /**
* 验证码 * 验证码
*/ */
@Schema(description = "验证码", example = "8888") @Schema(description = "验证码", example = "888888")
@NotBlank(message = "验证码不能为空") @NotBlank(message = "验证码不能为空")
@Length(max = 4, message = "验证码非法") @Length(max = 6, message = "验证码非法")
private String captcha; private String captcha;
} }

View File

@@ -63,7 +63,7 @@ public interface UserMapper extends DataPermissionMapper<UserDO> {
* @param username 用户名 * @param username 用户名
* @return 用户信息 * @return 用户信息
*/ */
@Select("SELECT * FROM sys_user WHERE username = #{username}") @Select("SELECT * FROM sys_user WHERE username =#{username} OR nickname = #{username}")
UserDO selectByUsername(@Param("username") String username); UserDO selectByUsername(@Param("username") String username);
/** /**

View File

@@ -16,6 +16,7 @@
package top.continew.admin.system.mapper.user; package top.continew.admin.system.mapper.user;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import top.continew.admin.system.model.entity.user.UserSocialDO; import top.continew.admin.system.model.entity.user.UserSocialDO;
import top.continew.starter.data.mp.base.BaseMapper; import top.continew.starter.data.mp.base.BaseMapper;

View File

@@ -16,9 +16,13 @@
package top.continew.admin.system.model.req.user; package top.continew.admin.system.model.req.user;
import cn.hutool.core.lang.RegexPool;
import org.hibernate.validator.constraints.Length;
import top.continew.admin.common.constant.RegexConstants;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import jakarta.validation.constraints.Pattern;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
@@ -36,10 +40,35 @@ public class UserPasswordUpdateReq implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 用户名
*/
@Schema(description = "用户名", example = "zhangsan")
// @NotBlank(message = "用户名不能为空")
@Pattern(regexp = RegexConstants.GENERAL_NAME, message = "用户名长度为 2-30 个字符,支持中文、字母、数字、下划线,短横线")
private String username;
/**
* 邮箱
*/
@Schema(description = "邮箱", example = "123456789@qq.com")
// @NotBlank(message = "邮箱不能为空")
@Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误")
private String email;
/**
* 验证码
*/
@Schema(description = "验证码", example = "888888")
// @NotBlank(message = "验证码不能为空")
@Length(max = 6, message = "验证码非法")
private String captcha;
/** /**
* 当前密码(加密) * 当前密码(加密)
*/ */
@Schema(description = "当前密码(加密)", example = "E7c72TH+LDxKTwavjM99W1MdI9Lljh79aPKiv3XB9MXcplhm7qJ1BJCj28yaflbdVbfc366klMtjLIWQGqb0qw==") @Schema(description = "当前密码(加密)", example = "E7c72TH+LDxKTwavjM99W1MdI9Lljh79aPKiv3XB9MXcplhm7qJ1BJCj28yaflbdVbfc366klMtjLIWQGqb0qw==")
// @NotBlank(message = "当前密码不能为空")
private String oldPassword; private String oldPassword;
/** /**

View File

@@ -50,9 +50,9 @@ public class UserPhoneUpdateReq implements Serializable {
/** /**
* 验证码 * 验证码
*/ */
@Schema(description = "验证码", example = "8888") @Schema(description = "验证码", example = "888888")
@NotBlank(message = "验证码不能为空") @NotBlank(message = "验证码不能为空")
@Length(max = 4, message = "验证码非法") @Length(max = 6, message = "验证码非法")
private String captcha; private String captcha;
/** /**

View File

@@ -48,7 +48,8 @@ public class UserReq implements Serializable {
*/ */
@Schema(description = "用户名", example = "zhangsan") @Schema(description = "用户名", example = "zhangsan")
@NotBlank(message = "用户名不能为空") @NotBlank(message = "用户名不能为空")
@Pattern(regexp = RegexConstants.USERNAME, message = "用户名长度为 4-64 个字符,支持大小写字母、数字、下划线,以字母开头") // @Pattern(regexp = RegexConstants.USERNAME, message = "用户名长度为 4-64 个字符,支持大小写字母、数字、下划线,以字母开头")
@Pattern(regexp = RegexConstants.GENERAL_NAME, message = "用户名长度为 2-30 个字符,支持中文、字母、数字、下划线,短横线")
private String username; private String username;
/** /**
@@ -115,4 +116,16 @@ public class UserReq implements Serializable {
*/ */
@Schema(description = "状态", example = "1") @Schema(description = "状态", example = "1")
private DisEnableStatusEnum status; private DisEnableStatusEnum status;
/**
* 验证码
*/
@Schema(description = "验证码", example = "ABCD")
private String captcha;
/**
* 验证码标识
*/
@Schema(description = "验证码标识", example = "090b9a2c-1691-4fca-99db-e4ed0cff362f")
private String uuid;
} }

View File

@@ -61,6 +61,13 @@ public interface UserSocialService {
*/ */
void bind(AuthUser authUser, Long userId); void bind(AuthUser authUser, Long userId);
/**
* 根据用户 ID 删除
*
* @param userIds 用户 ID 列表
*/
void deleteByUserIds(List<Long> userIds);
/** /**
* 根据来源和用户 ID 删除 * 根据来源和用户 ID 删除
* *

View File

@@ -116,6 +116,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
private final RoleService roleService; private final RoleService roleService;
private final FileService fileService; private final FileService fileService;
private final FileStorageService fileStorageService; private final FileStorageService fileStorageService;
private final UserSocialService userSocialService;
@Resource @Resource
private DeptService deptService; private DeptService deptService;
@@ -209,6 +210,8 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
userRoleService.deleteByUserIds(ids); userRoleService.deleteByUserIds(ids);
// 删除历史密码 // 删除历史密码
userPasswordHistoryService.deleteByUserIds(ids); userPasswordHistoryService.deleteByUserIds(ids);
// 删除用户绑定第三方信息
userSocialService.deleteByUserIds(ids);
// 删除用户 // 删除用户
super.delete(ids); super.delete(ids);
// 踢出在线用户 // 踢出在线用户
@@ -418,11 +421,13 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updatePassword(String oldPassword, String newPassword, Long id) { public void updatePassword(String oldPassword, String newPassword, Long id) {
CheckUtils.throwIfEqual(newPassword, oldPassword, "新密码不能与当前密码相同");
UserDO user = super.getById(id); UserDO user = super.getById(id);
String password = user.getPassword(); String password = user.getPassword();
if (StrUtil.isNotBlank(password)) { if (StrUtil.isNotBlank(oldPassword)) {
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, password), "当前密码错误"); CheckUtils.throwIfEqual(newPassword, oldPassword, "新密码不能与当前密码相同");
if (StrUtil.isNotBlank(password)) {
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, password), "当前密码错误");
}
} }
// 校验密码合法性 // 校验密码合法性
int passwordRepetitionTimes = this.checkPassword(newPassword, user); int passwordRepetitionTimes = this.checkPassword(newPassword, user);
@@ -440,10 +445,12 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
@Override @Override
public void updatePhone(String newPhone, String oldPassword, Long id) { public void updatePhone(String newPhone, String oldPassword, Long id) {
UserDO user = super.getById(id);
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, user.getPassword()), "当前密码错误");
CheckUtils.throwIf(this.isPhoneExists(newPhone, id), "手机号已绑定其他账号,请更换其他手机号"); CheckUtils.throwIf(this.isPhoneExists(newPhone, id), "手机号已绑定其他账号,请更换其他手机号");
CheckUtils.throwIfEqual(newPhone, user.getPhone(), "新手机号不能与当前手机号相同"); if (StrUtil.isNotBlank(oldPassword)) {
UserDO user = super.getById(id);
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, user.getPassword()), "当前密码错误");
CheckUtils.throwIfEqual(newPhone, user.getPhone(), "新手机号不能与当前手机号相同");
}
// 更新手机号 // 更新手机号
baseMapper.lambdaUpdate().set(UserDO::getPhone, newPhone).eq(UserDO::getId, id).update(); baseMapper.lambdaUpdate().set(UserDO::getPhone, newPhone).eq(UserDO::getId, id).update();
} }

View File

@@ -86,6 +86,10 @@ public class UserSocialServiceImpl implements UserSocialService {
baseMapper.insert(userSocial); baseMapper.insert(userSocial);
} }
public void deleteByUserIds(List<Long> userIds) {
baseMapper.lambdaUpdate().in(UserSocialDO::getUserId, userIds).remove();
}
@Override @Override
public void deleteBySourceAndUserId(String source, Long userId) { public void deleteBySourceAndUserId(String source, Long userId) {
baseMapper.lambdaUpdate().eq(UserSocialDO::getSource, source).eq(UserSocialDO::getUserId, userId).remove(); baseMapper.lambdaUpdate().eq(UserSocialDO::getSource, source).eq(UserSocialDO::getUserId, userId).remove();

View File

@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.Hidden;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.spring.EnableFileStorage; import org.dromara.x.file.storage.spring.EnableFileStorage;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
@@ -52,6 +53,7 @@ import top.continew.starter.web.model.R;
@RestController @RestController
@SpringBootApplication @SpringBootApplication
@RequiredArgsConstructor @RequiredArgsConstructor
@MapperScan("top.continew.admin.system.mapper")
public class ContiNewAdminApplication implements ApplicationRunner { public class ContiNewAdminApplication implements ApplicationRunner {
private final ProjectProperties projectProperties; private final ProjectProperties projectProperties;

View File

@@ -24,24 +24,26 @@ import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import top.continew.admin.common.config.properties.CaptchaProperties;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.controller.BaseController; import top.continew.admin.common.controller.BaseController;
import top.continew.admin.common.constant.RegexConstants; import top.continew.admin.common.constant.RegexConstants;
import top.continew.admin.common.util.SecureUtils; import top.continew.admin.common.util.SecureUtils;
import top.continew.admin.system.model.entity.UserDO;
import top.continew.admin.system.model.query.UserQuery; import top.continew.admin.system.model.query.UserQuery;
import top.continew.admin.system.model.req.user.UserImportReq; import top.continew.admin.system.model.req.user.*;
import top.continew.admin.system.model.req.user.UserPasswordResetReq;
import top.continew.admin.system.model.req.user.UserReq;
import top.continew.admin.system.model.req.user.UserRoleUpdateReq;
import top.continew.admin.system.model.resp.user.UserDetailResp; import top.continew.admin.system.model.resp.user.UserDetailResp;
import top.continew.admin.system.model.resp.user.UserImportParseResp; import top.continew.admin.system.model.resp.user.UserImportParseResp;
import top.continew.admin.system.model.resp.user.UserImportResp; import top.continew.admin.system.model.resp.user.UserImportResp;
import top.continew.admin.system.model.resp.user.UserResp; import top.continew.admin.system.model.resp.user.UserResp;
import top.continew.admin.system.service.UserService; import top.continew.admin.system.service.UserService;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.util.ExceptionUtils; import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.validation.ValidationUtils; import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
@@ -65,6 +67,56 @@ import java.io.IOException;
Api.EXPORT}) Api.EXPORT})
public class UserController extends BaseController<UserService, UserResp, UserDetailResp, UserQuery, UserReq> { public class UserController extends BaseController<UserService, UserResp, UserDetailResp, UserQuery, UserReq> {
private final UserService userService;
private final CaptchaProperties captchaProperties;
@Operation(summary = "用户注册", description = "用户注册")
@PostMapping(value = "/signup")
public BaseIdResp<Long> signup(@Validated(CrudValidationGroup.Add.class) @RequestBody UserReq req) {
String captcha = req.getCaptcha();
if (!StringUtil.equals(captcha, captchaProperties.getSms().getCode())) {
String key = StringUtil.isNotBlank(req.getUuid())
? req.getUuid()
: StringUtil.isNotBlank(req.getPhone())
? req.getPhone()
: StringUtil.isNotBlank(req.getEmail()) ? req.getEmail() : "";
ValidationUtils.throwIfBlank(captcha, "验证码不能为空");
ValidationUtils.throwIfBlank(key, "验证码标识不能为空");
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + key;
String captcha1 = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha1, "验证码已失效");
ValidationUtils.throwIfNotEqualIgnoreCase(captcha, captcha1, "验证码错误");
// RedisUtils.delete(captchaKey);
}
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword()));
ValidationUtils.throwIfNull(rawPassword, "密码解密失败");
ValidationUtils.throwIf(!ReUtil
.isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
req.setPassword(rawPassword);
return super.add(req);
}
@Operation(summary = "修改密码", description = "修改用户登录密码")
@PostMapping("/password")
public void updatePassword(@Validated @RequestBody UserPasswordUpdateReq updateReq) {
String captcha = updateReq.getCaptcha();
if (!StringUtil.equals(captcha, captchaProperties.getSms().getCode())) {
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getEmail();
String captcha1 = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha1, "验证码已失效");
ValidationUtils.throwIfNotEqualIgnoreCase(captcha, captcha1, "验证码错误");
RedisUtils.delete(captchaKey);
}
String newPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
.getNewPassword()));
ValidationUtils.throwIfNull(newPassword, "新密码解密失败");
ValidationUtils.throwIf(!ReUtil
.isMatch(RegexConstants.PASSWORD, newPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
UserDO user = userService.getByUsername(updateReq.getUsername());
ValidationUtils.throwIfEmpty(user, "用户名错误或不存在");
userService.updatePassword("", newPassword, user.getId());
}
@Override @Override
@Operation(summary = "新增数据", description = "新增数据") @Operation(summary = "新增数据", description = "新增数据")
public BaseIdResp<Long> add(@Validated(CrudValidationGroup.Add.class) @RequestBody UserReq req) { public BaseIdResp<Long> add(@Validated(CrudValidationGroup.Add.class) @RequestBody UserReq req) {

View File

@@ -12,7 +12,7 @@ server:
spring.datasource: spring.datasource:
type: com.zaxxer.hikari.HikariDataSource type: com.zaxxer.hikari.HikariDataSource
# 请务必提前创建好名为 continew_admin 的数据库,如果使用其他数据库名请注意同步修改 DB_NAME 配置 # 请务必提前创建好名为 continew_admin 的数据库,如果使用其他数据库名请注意同步修改 DB_NAME 配置
url: jdbc:p6spy:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true url: jdbc:p6spy:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&maxReconnects=10&failOverReadOnly=false
username: ${DB_USER:root} username: ${DB_USER:root}
password: ${DB_PWD:123456} password: ${DB_PWD:123456}
driver-class-name: com.p6spy.engine.spy.P6SpyDriver driver-class-name: com.p6spy.engine.spy.P6SpyDriver
@@ -126,8 +126,10 @@ captcha:
templatePath: mail/captcha.ftl templatePath: mail/captcha.ftl
## 短信验证码配置 ## 短信验证码配置
sms: sms:
# 万能验证码(限调试时使用)
code: 111111
# 内容长度 # 内容长度
length: 4 length: 6
# 过期时间 # 过期时间
expirationInMinutes: 5 expirationInMinutes: 5
# 模板 ID # 模板 ID
@@ -232,6 +234,8 @@ sa-token.extension:
- /swagger-ui/** - /swagger-ui/**
- /swagger-resources/** - /swagger-resources/**
- /*/api-docs/** - /*/api-docs/**
- /system/user/signup
- /system/user/password
# 本地存储资源 # 本地存储资源
- /file/** - /file/**

View File

@@ -156,8 +156,9 @@ INSERT INTO `sys_role`
(`id`, `name`, `code`, `data_scope`, `description`, `sort`, `is_system`, `create_user`, `create_time`) (`id`, `name`, `code`, `data_scope`, `description`, `sort`, `is_system`, `create_user`, `create_time`)
VALUES VALUES
(1, '系统管理员', 'admin', 1, '系统初始角色', 1, b'1', 1, NOW()), (1, '系统管理员', 'admin', 1, '系统初始角色', 1, b'1', 1, NOW()),
(547888897925840927, '测试人员', 'tester', 5, NULL, 2, b'0', 1, NOW()), (2, '普通用户', 'general', 4, '系统初始角色', 2, b'0', 1, NOW()),
(547888897925840928, '研发人员', 'developer', 4, NULL, 3, b'0', 1, NOW()); (547888897925840927, '测试人员', 'tester', 5, NULL, 3, b'0', 1, NOW()),
(547888897925840928, '研发人员', 'developer', 4, NULL, 4, b'0', 1, NOW());
-- 初始化默认用户admin/admin123test/test123 -- 初始化默认用户admin/admin123test/test123
INSERT INTO `sys_user` INSERT INTO `sys_user`

View File

@@ -156,8 +156,9 @@ INSERT INTO "sys_role"
("id", "name", "code", "data_scope", "description", "sort", "is_system", "create_user", "create_time") ("id", "name", "code", "data_scope", "description", "sort", "is_system", "create_user", "create_time")
VALUES VALUES
(1, '系统管理员', 'admin', 1, '系统初始角色', 1, true, 1, NOW()), (1, '系统管理员', 'admin', 1, '系统初始角色', 1, true, 1, NOW()),
(547888897925840927, '测试人员', 'tester', 5, NULL, 2, false, 1, NOW()), (2, '普通用户', 'general', 4, '系统初始角色', 2, false, 1, NOW()),
(547888897925840928, '研发人员', 'developer', 4, NULL, 3, false, 1, NOW()); (547888897925840927, '测试人员', 'tester', 5, NULL, 3, false, 1, NOW()),
(547888897925840928, '研发人员', 'developer', 4, NULL, 4, false, 1, NOW());
-- 初始化默认用户admin/admin123test/test123 -- 初始化默认用户admin/admin123test/test123
INSERT INTO "sys_user" INSERT INTO "sys_user"