feat: 实现邮箱验证码功能(注册、修改密码、修改邮箱)

- UserInfoService 新增 sendEmailCodeForRegister、sendEmailCodeForUpdateEmail、checkEmailCode 方法
- 三种场景使用不同缓存前缀区分:
  - 注册:email_code_register:{email}
  - 修改密码:email_code:{userId}
  - 修改邮箱:email_code_update_email:{userId}
- AppUserLoginController 新增 /sendEmailCodeForRegister 公开接口
- AppUserInfoController 新增 /sendEmailCodeForUpdateEmail 接口
- /bindEmail、/updateEmail、/updatePassword 增加验证码验证
This commit is contained in:
OpenCode
2026-07-23 13:41:00 +08:00
parent 1ecb285fd0
commit 80dc8a0c07
4 changed files with 89 additions and 13 deletions
@@ -44,7 +44,7 @@ public class AppUserInfoController {
);
}
@Operation(summary = "发送邮箱验证码")
@Operation(summary = "发送邮箱验证码(修改密码)")
@PostMapping("/sendEmailCode")
public R sendEmailCode() {
Long userId = CoolSecurityUtil.getCurrentUserId();
@@ -52,6 +52,15 @@ public class AppUserInfoController {
return R.ok();
}
@Operation(summary = "发送邮箱验证码(修改邮箱)")
@PostMapping("/sendEmailCodeForUpdateEmail")
public R sendEmailCodeForUpdateEmail(@RequestAttribute JSONObject requestParams) {
Long userId = CoolSecurityUtil.getCurrentUserId();
String email = requestParams.getStr("email");
userInfoService.sendEmailCodeForUpdateEmail(userId, email, emailSendService);
return R.ok();
}
@Operation(summary = "更新用户密码")
@PostMapping("/updatePassword")
public R updatePassword(
@@ -84,7 +93,8 @@ public class AppUserInfoController {
@PostMapping("/bindEmail")
public R bindEmail(@RequestAttribute JSONObject requestParams) {
String email = requestParams.getStr("email");
userInfoService.bindEmail(CoolSecurityUtil.getCurrentUserId(), email);
String code = requestParams.getStr("code");
userInfoService.bindEmail(CoolSecurityUtil.getCurrentUserId(), email, code);
return R.ok();
}
@@ -100,7 +110,8 @@ public class AppUserInfoController {
@PostMapping("/updateEmail")
public R updateEmail(@RequestAttribute JSONObject requestParams) {
String email = requestParams.getStr("email");
userInfoService.updateEmail(CoolSecurityUtil.getCurrentUserId(), email);
String code = requestParams.getStr("code");
userInfoService.updateEmail(CoolSecurityUtil.getCurrentUserId(), email, code);
return R.ok();
}
}
@@ -6,10 +6,12 @@ import com.cool.core.enums.UserTypeEnum;
import com.cool.core.exception.CoolPreconditions;
import com.cool.core.request.R;
import com.cool.modules.base.service.sys.BaseSysLoginService;
import com.cool.modules.base.service.sys.EmailSendService;
import com.cool.modules.user.controller.app.params.CaptchaParam;
import com.cool.modules.user.controller.app.params.LoginParam;
import com.cool.modules.user.controller.app.params.RefreshTokenParam;
import com.cool.modules.user.controller.app.params.SmsCodeParam;
import com.cool.modules.user.service.UserInfoService;
import com.cool.modules.user.service.UserLoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -28,6 +30,10 @@ public class AppUserLoginController {
private final BaseSysLoginService baseSysLoginService;
private final UserInfoService userInfoService;
private final EmailSendService emailSendService;
/**
* 小程序登录
*/
@@ -215,11 +221,25 @@ public class AppUserLoginController {
String email = param.getEmail();
String password = param.getPassword();
String nickName = param.getNickName();
String code = param.getSmsCode();
CoolPreconditions.checkEmpty(email);
CoolPreconditions.checkEmpty(password);
CoolPreconditions.checkEmpty(code);
userInfoService.checkEmailCode(
com.cool.modules.user.service.impl.UserInfoServiceImpl.getRegisterCacheKey(email), code);
return R.ok(userLoginService.emailRegister(email, password, nickName));
}
@TokenIgnore
@Operation(summary = "发送邮箱验证码(注册)")
@PostMapping("/sendEmailCodeForRegister")
public R sendEmailCodeForRegister(@RequestBody LoginParam param) {
String email = param.getEmail();
CoolPreconditions.checkEmpty(email);
userInfoService.sendEmailCodeForRegister(email, emailSendService);
return R.ok();
}
@TokenIgnore
@Operation(summary = "用户名注册")
@PostMapping("/usernameRegister")
@@ -11,13 +11,19 @@ public interface UserInfoService extends BaseService<UserInfoEntity> {
void sendEmailCode(Long userId, EmailSendService emailSendService);
void sendEmailCodeForRegister(String email, EmailSendService emailSendService);
void sendEmailCodeForUpdateEmail(Long userId, String newEmail, EmailSendService emailSendService);
void checkEmailCode(String cacheKey, String code);
void updatePasswordByEmail(Long userId, String password, String code);
void logoff(Long currentUserId);
void bindPhone(Long currentUserId, String phone, String code);
void bindEmail(Long currentUserId, String email);
void bindEmail(Long currentUserId, String email, String code);
void bindUsername(Long currentUserId, String username);
@@ -31,5 +37,5 @@ public interface UserInfoService extends BaseService<UserInfoEntity> {
void checkUsernameUnique(String username, Long excludeId);
void updateEmail(Long currentUserId, String email);
void updateEmail(Long currentUserId, String email, String code);
}
@@ -26,6 +26,16 @@ public class UserInfoServiceImpl extends BaseServiceImpl<UserInfoMapper, UserInf
private final CoolCache coolCache;
private static final String EMAIL_CODE_CACHE_PREFIX = "email_code:";
private static final String EMAIL_CODE_REGISTER_PREFIX = "email_code_register:";
private static final String EMAIL_CODE_UPDATE_EMAIL_PREFIX = "email_code_update_email:";
public static String getRegisterCacheKey(String email) {
return EMAIL_CODE_REGISTER_PREFIX + email;
}
public static String getUpdateEmailCacheKey(Long userId) {
return EMAIL_CODE_UPDATE_EMAIL_PREFIX + userId;
}
@Override
public UserInfoEntity person(Long userId) {
@@ -56,17 +66,44 @@ public class UserInfoServiceImpl extends BaseServiceImpl<UserInfoMapper, UserInf
emailSendService.sendCode(info.getEmail(), code);
}
@Override
public void sendEmailCodeForRegister(String email, EmailSendService emailSendService) {
CoolPreconditions.check(StrUtil.isEmpty(email), "邮箱不能为空");
String code = RandomUtil.randomNumbers(6);
String cacheKey = getRegisterCacheKey(email);
coolCache.set(cacheKey, code, 600);
emailSendService.sendCode(email, code);
}
@Override
public void sendEmailCodeForUpdateEmail(Long userId, String newEmail, EmailSendService emailSendService) {
CoolPreconditions.check(StrUtil.isEmpty(newEmail), "新邮箱不能为空");
String code = RandomUtil.randomNumbers(6);
String cacheKey = getUpdateEmailCacheKey(userId);
coolCache.set(cacheKey, code, 600);
emailSendService.sendCode(newEmail, code);
}
@Override
public void checkEmailCode(String cacheKey, String code) {
Object cachedCode = coolCache.get(cacheKey);
CoolPreconditions.check(ObjUtil.isEmpty(cachedCode), "验证码已过期,请重新获取");
CoolPreconditions.check(!ObjUtil.equals(String.valueOf(cachedCode), code), "验证码错误");
coolCache.del(cacheKey);
}
@Override
public void updatePasswordByEmail(Long userId, String password, String code) {
UserInfoEntity info = getById(userId);
CoolPreconditions.checkEmpty(info, "用户不存在");
String cacheKey = EMAIL_CODE_CACHE_PREFIX + userId;
Object cachedCode = coolCache.get(cacheKey);
CoolPreconditions.check(ObjUtil.isEmpty(cachedCode), "验证码已过期,请重新获取");
CoolPreconditions.check(!ObjUtil.equals(String.valueOf(cachedCode), code), "验证码错误");
coolCache.del(cacheKey);
checkEmailCode(EMAIL_CODE_CACHE_PREFIX + userId, code);
info.setPassword(MD5.create().digestHex(password));
info.updateById();
@@ -114,7 +151,7 @@ public class UserInfoServiceImpl extends BaseServiceImpl<UserInfoMapper, UserInf
}
@Override
public void bindEmail(Long userId, String email) {
public void bindEmail(Long userId, String email, String code) {
UserInfoEntity info = getById(userId);
CoolPreconditions.checkEmpty(info, "用户不存在");
CoolPreconditions.check(ObjUtil.isNotEmpty(info.getEmail()), "该用户已绑定邮箱");
@@ -122,6 +159,7 @@ public class UserInfoServiceImpl extends BaseServiceImpl<UserInfoMapper, UserInf
.eq(UserInfoEntity::getEmail, email)
.ne(UserInfoEntity::getStatus, 2));
CoolPreconditions.check(ObjUtil.isNotEmpty(existing), "该邮箱已被其他用户使用");
checkEmailCode(getRegisterCacheKey(email), code);
info.setEmail(email);
info.updateById();
}
@@ -166,10 +204,11 @@ public class UserInfoServiceImpl extends BaseServiceImpl<UserInfoMapper, UserInf
}
@Override
public void updateEmail(Long userId, String email) {
public void updateEmail(Long userId, String email, String code) {
UserInfoEntity info = getById(userId);
CoolPreconditions.checkEmpty(info, "用户不存在");
checkEmailUnique(email, userId);
checkEmailCode(getUpdateEmailCacheKey(userId), code);
info.setEmail(email);
info.updateById();
}