feat(auth): bind code to the requesting user

Store the username and email alongside the code in the cached
EmailVerificationCode object, and reject registration when the
username or email no longer match the original request.
This commit is contained in:
siujamo committed 2026-08-21 09:31:37 +08:00
1 parent 812ab0ba91
commit ffcd234221
2 files changed
+29 -5

No files matched your search

@@ -0,0 +1,8 @@
package com.onixbyte.deltaforceguide.domain.dto;
public record EmailVerificationCode(
String username,
String email,
String code
) {
}
@@ -3,6 +3,7 @@ package com.onixbyte.deltaforceguide.service;
import com.onixbyte.captcha.text.TextProducer; import com.onixbyte.captcha.text.TextProducer;
import com.onixbyte.deltaforceguide.client.EmailClient; import com.onixbyte.deltaforceguide.client.EmailClient;
import com.onixbyte.deltaforceguide.client.TokenClient; import com.onixbyte.deltaforceguide.client.TokenClient;
import com.onixbyte.deltaforceguide.domain.dto.EmailVerificationCode;
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest; import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
import com.onixbyte.deltaforceguide.domain.dto.RegisterRequest; import com.onixbyte.deltaforceguide.domain.dto.RegisterRequest;
import com.onixbyte.deltaforceguide.domain.dto.SendVerificationCodeRequest; import com.onixbyte.deltaforceguide.domain.dto.SendVerificationCodeRequest;
@@ -118,13 +119,24 @@ public class AuthService {
var code = request.verificationCode(); var code = request.verificationCode();
var verificationCodeId = request.verificationCodeId(); var verificationCodeId = request.verificationCodeId();
var storedCode = redisTemplate.opsForValue().get("verification-code:" + verificationCodeId); var _req = redisTemplate.opsForValue().get("verification-code:" + verificationCodeId);
if (!(storedCode instanceof String strStoredCode)) { if (!(_req instanceof EmailVerificationCode verificationCode)) {
log.error("storedCode not a String, storedCode={}", storedCode); log.error("_req not a EmailVerificationCode, storedCode={}", _req);
throw new InternalServerErrorException("系统内部错误,请重试"); throw new InternalServerErrorException("系统内部错误,请重试");
} }
if (!code.equalsIgnoreCase(strStoredCode)) { if (!request.username().equals(verificationCode.username())
|| !request.email().equals(verificationCode.email())) {
log.error(
"Username and email address do not match the data submitted "
+ "when requesting the verification code."
);
log.error("EmailVerificationCode={}", verificationCode);
log.error("RegisterRequest={}", request);
throw new BadRequestException("用户名或邮箱与获取验证码时不一致,请重新获取验证码。");
}
if (!code.equalsIgnoreCase(verificationCode.code())) {
throw new BadRequestException("邮箱验证码不正确,请重试。"); throw new BadRequestException("邮箱验证码不正确,请重试。");
} }
@@ -189,7 +201,11 @@ public class AuthService {
var code = textProducer.getText(); var code = textProducer.getText();
// Save verification code to cache. // Save verification code to cache.
redisTemplate.opsForValue().set("verification-code:" + uuid, code, Duration.ofMinutes(10L)); redisTemplate.opsForValue().set(
"verification-code:" + uuid,
new EmailVerificationCode(request.username(), request.email(), code),
Duration.ofMinutes(10L)
);
// Send email. // Send email.
emailClient.sendVerificationCode(request.email(), request.username(), code, 10); emailClient.sendVerificationCode(request.email(), request.username(), code, 10);