验证码修改
This commit is contained in:
@@ -128,7 +128,8 @@ public class AuthController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 发送邮箱验证码
|
* @description 发送邮箱验证码
|
||||||
* @param requestBody 包含email字段的请求体
|
* @param requestBody 包含email和scene字段的请求体
|
||||||
|
* scene: 业务场景(login-登录, register-注册, reset-找回密码, bind-绑定邮箱等)
|
||||||
* @return ResultDomain<Boolean> 发送结果
|
* @return ResultDomain<Boolean> 发送结果
|
||||||
* @author yslg
|
* @author yslg
|
||||||
* @since 2025-11-03
|
* @since 2025-11-03
|
||||||
@@ -138,6 +139,7 @@ public class AuthController {
|
|||||||
ResultDomain<Map<String, String>> result = new ResultDomain<>();
|
ResultDomain<Map<String, String>> result = new ResultDomain<>();
|
||||||
|
|
||||||
String email = requestBody.get("email");
|
String email = requestBody.get("email");
|
||||||
|
String scene = requestBody.get("scene");
|
||||||
|
|
||||||
// 验证邮箱格式
|
// 验证邮箱格式
|
||||||
if (email == null || email.trim().isEmpty()) {
|
if (email == null || email.trim().isEmpty()) {
|
||||||
@@ -151,10 +153,15 @@ public class AuthController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证场景参数
|
||||||
|
if (scene == null || scene.trim().isEmpty()) {
|
||||||
|
scene = "default";
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否频繁发送(60秒内只能发送一次)
|
// 检查是否频繁发送(60秒内只能发送一次)
|
||||||
String rateLimitKey = "email:code:ratelimit:" + email;
|
String rateLimitKey = "email:code:ratelimit:" + scene + ":" + email;
|
||||||
if (redisService.hasKey(rateLimitKey)) {
|
if (redisService.hasKey(rateLimitKey)) {
|
||||||
result.fail("验证码已发送,请勿重复发送");
|
result.fail("验证码已发送,请60秒后再试");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,21 +175,25 @@ public class AuthController {
|
|||||||
boolean success = emailUtils.sendVerificationCode(email, code);
|
boolean success = emailUtils.sendVerificationCode(email, code);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// 将验证码存储到Redis,绑定sessionId,有效期5分钟
|
// 将验证码存储到Redis,绑定sessionId和业务场景,有效期5分钟
|
||||||
String codeKey = "email:code:" + sessionId;
|
String codeKey = "email:code:" + scene + ":" + sessionId;
|
||||||
String codeValue = email + ":" + code; // 格式:邮箱:验证码
|
String codeValue = email + ":" + code;
|
||||||
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
||||||
|
|
||||||
// 设置5分钟的发送频率限制
|
// 设置60秒的发送频率限制
|
||||||
redisService.set(rateLimitKey, "1", 5, TimeUnit.MINUTES);
|
redisService.set(rateLimitKey, "1", 60, TimeUnit.SECONDS);
|
||||||
|
|
||||||
// 返回sessionId给前端
|
// 计算过期时间戳(当前时间 + 5分钟)
|
||||||
|
long expireTime = System.currentTimeMillis() + (5 * 60 * 1000);
|
||||||
|
|
||||||
|
// 返回sessionId和过期时间给前端
|
||||||
Map<String, String> data = Map.of(
|
Map<String, String> data = Map.of(
|
||||||
"sessionId", sessionId,
|
"sessionId", sessionId,
|
||||||
|
"expireTime", String.valueOf(expireTime),
|
||||||
"message", "验证码已发送到邮箱"
|
"message", "验证码已发送到邮箱"
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info("邮箱验证码已发送,邮箱: {}, sessionId: {}", email, sessionId);
|
logger.info("邮箱验证码已发送,邮箱: {}, scene: {}, sessionId: {}, expireTime: {}", email, scene, sessionId, expireTime);
|
||||||
result.success("验证码已发送到邮箱", data);
|
result.success("验证码已发送到邮箱", data);
|
||||||
} else {
|
} else {
|
||||||
result.fail("验证码发送失败,请稍后重试");
|
result.fail("验证码发送失败,请稍后重试");
|
||||||
@@ -193,7 +204,8 @@ public class AuthController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 发送手机验证码
|
* @description 发送手机验证码
|
||||||
* @param requestBody 包含phone字段的请求体
|
* @param requestBody 包含phone和scene字段的请求体
|
||||||
|
* scene: 业务场景(login-登录, register-注册, reset-找回密码, bind-绑定手机等)
|
||||||
* @return ResultDomain<Boolean> 发送结果
|
* @return ResultDomain<Boolean> 发送结果
|
||||||
* @author yslg
|
* @author yslg
|
||||||
* @since 2025-11-03
|
* @since 2025-11-03
|
||||||
@@ -203,6 +215,7 @@ public class AuthController {
|
|||||||
ResultDomain<Map<String, String>> result = new ResultDomain<>();
|
ResultDomain<Map<String, String>> result = new ResultDomain<>();
|
||||||
|
|
||||||
String phone = requestBody.get("phone");
|
String phone = requestBody.get("phone");
|
||||||
|
String scene = requestBody.get("scene");
|
||||||
|
|
||||||
// 验证手机号格式
|
// 验证手机号格式
|
||||||
if (phone == null || phone.trim().isEmpty()) {
|
if (phone == null || phone.trim().isEmpty()) {
|
||||||
@@ -215,10 +228,15 @@ public class AuthController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证场景参数
|
||||||
|
if (scene == null || scene.trim().isEmpty()) {
|
||||||
|
scene = "default";
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否频繁发送(60秒内只能发送一次)
|
// 检查是否频繁发送(60秒内只能发送一次)
|
||||||
String rateLimitKey = "sms:code:ratelimit:" + phone;
|
String rateLimitKey = "sms:code:ratelimit:" + scene + ":" + phone;
|
||||||
if (redisService.hasKey(rateLimitKey)) {
|
if (redisService.hasKey(rateLimitKey)) {
|
||||||
result.fail("验证码已发送,请勿重复发送");
|
result.fail("验证码已发送,请60秒后再试");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,21 +250,25 @@ public class AuthController {
|
|||||||
boolean success = smsUtils.sendVerificationCode(phone, code);
|
boolean success = smsUtils.sendVerificationCode(phone, code);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// 将验证码存储到Redis,绑定sessionId,有效期5分钟
|
// 将验证码存储到Redis,绑定sessionId和业务场景,有效期5分钟
|
||||||
String codeKey = "sms:code:" + sessionId;
|
String codeKey = "sms:code:" + scene + ":" + sessionId;
|
||||||
String codeValue = phone + ":" + code; // 格式:手机号:验证码
|
String codeValue = phone + ":" + code;
|
||||||
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
||||||
|
|
||||||
// 设置5分钟的发送频率限制
|
// 设置60秒的发送频率限制
|
||||||
redisService.set(rateLimitKey, "1", 5, TimeUnit.MINUTES);
|
redisService.set(rateLimitKey, "1", 60, TimeUnit.SECONDS);
|
||||||
|
|
||||||
// 返回sessionId给前端
|
// 计算过期时间戳(当前时间 + 5分钟)
|
||||||
|
long expireTime = System.currentTimeMillis() + (5 * 60 * 1000);
|
||||||
|
|
||||||
|
// 返回sessionId和过期时间给前端
|
||||||
Map<String, String> data = Map.of(
|
Map<String, String> data = Map.of(
|
||||||
"sessionId", sessionId,
|
"sessionId", sessionId,
|
||||||
|
"expireTime", String.valueOf(expireTime),
|
||||||
"message", "验证码已发送"
|
"message", "验证码已发送"
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info("短信验证码已发送,手机号: {}, sessionId: {}", phone, sessionId);
|
logger.info("短信验证码已发送,手机号: {}, scene: {}, sessionId: {}, expireTime: {}", phone, scene, sessionId, expireTime);
|
||||||
result.success("验证码已发送", data);
|
result.success("验证码已发送", data);
|
||||||
} else {
|
} else {
|
||||||
result.fail("验证码发送失败,请稍后重试");
|
result.fail("验证码发送失败,请稍后重试");
|
||||||
@@ -337,8 +359,8 @@ public class AuthController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过sessionId验证手机验证码
|
// 通过sessionId验证手机验证码(注册场景)
|
||||||
String smsCodeKey = "sms:code:" + smsSessionId;
|
String smsCodeKey = "sms:code:register:" + smsSessionId;
|
||||||
String storedSmsValue = (String) redisService.get(smsCodeKey);
|
String storedSmsValue = (String) redisService.get(smsCodeKey);
|
||||||
if (storedSmsValue == null) {
|
if (storedSmsValue == null) {
|
||||||
result.fail("验证码已过期,请重新获取");
|
result.fail("验证码已过期,请重新获取");
|
||||||
@@ -393,8 +415,8 @@ public class AuthController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过sessionId验证邮箱验证码
|
// 通过sessionId验证邮箱验证码(注册场景)
|
||||||
String emailCodeKey = "email:code:" + emailSessionId;
|
String emailCodeKey = "email:code:register:" + emailSessionId;
|
||||||
String storedEmailValue = (String) redisService.get(emailCodeKey);
|
String storedEmailValue = (String) redisService.get(emailCodeKey);
|
||||||
if (storedEmailValue == null) {
|
if (storedEmailValue == null) {
|
||||||
result.fail("验证码已过期,请重新获取");
|
result.fail("验证码已过期,请重新获取");
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ public class EmailLoginStrategy implements LoginStrategy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从Redis获取验证码
|
// 从Redis获取验证码(登录场景)
|
||||||
String codeKey = "email:code:" + captchaId;
|
String codeKey = "email:code:login:" + captchaId;
|
||||||
String storedValue = (String) redisService.get(codeKey);
|
String storedValue = (String) redisService.get(codeKey);
|
||||||
|
|
||||||
if (storedValue == null) {
|
if (storedValue == null) {
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ public class PhoneLoginStrategy implements LoginStrategy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从Redis获取验证码
|
// 从Redis获取验证码(登录场景)
|
||||||
String codeKey = "sms:code:" + captchaId;
|
String codeKey = "sms:code:login:" + captchaId;
|
||||||
String storedValue = (String) redisService.get(codeKey);
|
String storedValue = (String) redisService.get(codeKey);
|
||||||
|
|
||||||
if (storedValue == null) {
|
if (storedValue == null) {
|
||||||
|
|||||||
@@ -61,20 +61,22 @@ export const authApi = {
|
|||||||
/**
|
/**
|
||||||
* 发送手机验证码
|
* 发送手机验证码
|
||||||
* @param phone 手机号
|
* @param phone 手机号
|
||||||
* @returns Promise<ResultDomain<{sessionId: string, message: string}>>
|
* @param scene 业务场景(login-登录, register-注册, reset-找回密码, bind-绑定手机等)
|
||||||
|
* @returns Promise<ResultDomain<{sessionId: string, expireTime: string, message: string}>>
|
||||||
*/
|
*/
|
||||||
async sendSmsCode(phone: string): Promise<ResultDomain<{sessionId: string, message: string}>> {
|
async sendSmsCode(phone: string, scene: string = 'default'): Promise<ResultDomain<{sessionId: string, expireTime: string, message: string}>> {
|
||||||
const response = await api.post<{sessionId: string, message: string}>('/auth/send-sms-code', { phone });
|
const response = await api.post<{sessionId: string, expireTime: string, message: string}>('/auth/send-sms-code', { phone, scene });
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送邮箱验证码
|
* 发送邮箱验证码
|
||||||
* @param email 邮箱
|
* @param email 邮箱
|
||||||
* @returns Promise<ResultDomain<{sessionId: string, message: string}>>
|
* @param scene 业务场景(login-登录, register-注册, reset-找回密码, bind-绑定邮箱等)
|
||||||
|
* @returns Promise<ResultDomain<{sessionId: string, expireTime: string, message: string}>>
|
||||||
*/
|
*/
|
||||||
async sendEmailCode(email: string): Promise<ResultDomain<{sessionId: string, message: string}>> {
|
async sendEmailCode(email: string, scene: string = 'default'): Promise<ResultDomain<{sessionId: string, expireTime: string, message: string}>> {
|
||||||
const response = await api.post<{sessionId: string, message: string}>('/auth/send-email-code', { email });
|
const response = await api.post<{sessionId: string, expireTime: string, message: string}>('/auth/send-email-code', { email, scene });
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ const handleSendSmsCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendSmsCode(forgotForm.phone);
|
const result = await authApi.sendSmsCode(forgotForm.phone, 'reset');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
forgotForm.smsSessionId = result.data.sessionId;
|
forgotForm.smsSessionId = result.data.sessionId;
|
||||||
@@ -354,7 +354,7 @@ const handleSendEmailCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendEmailCode(forgotForm.email);
|
const result = await authApi.sendEmailCode(forgotForm.email, 'reset');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
forgotForm.emailSessionId = result.data.sessionId;
|
forgotForm.emailSessionId = result.data.sessionId;
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ const handleSendSmsCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendSmsCode(forgotForm.phone);
|
const result = await authApi.sendSmsCode(forgotForm.phone, 'reset');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
forgotForm.smsSessionId = result.data.sessionId;
|
forgotForm.smsSessionId = result.data.sessionId;
|
||||||
@@ -353,7 +353,7 @@ const handleSendEmailCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendEmailCode(forgotForm.email);
|
const result = await authApi.sendEmailCode(forgotForm.email, 'reset');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
forgotForm.emailSessionId = result.data.sessionId;
|
forgotForm.emailSessionId = result.data.sessionId;
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ const handleSendSmsCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendSmsCode(loginForm.phone);
|
const result = await authApi.sendSmsCode(loginForm.phone, 'login');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
loginForm.captchaId = result.data.sessionId;
|
loginForm.captchaId = result.data.sessionId;
|
||||||
@@ -396,7 +396,7 @@ const handleSendEmailCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendEmailCode(loginForm.email);
|
const result = await authApi.sendEmailCode(loginForm.email, 'login');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
loginForm.captchaId = result.data.sessionId;
|
loginForm.captchaId = result.data.sessionId;
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ const handleSendSmsCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendSmsCode(loginForm.phone);
|
const result = await authApi.sendSmsCode(loginForm.phone, 'login');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
loginForm.captchaId = result.data.sessionId;
|
loginForm.captchaId = result.data.sessionId;
|
||||||
@@ -396,7 +396,7 @@ const handleSendEmailCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendEmailCode(loginForm.email);
|
const result = await authApi.sendEmailCode(loginForm.email, 'login');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
loginForm.captchaId = result.data.sessionId;
|
loginForm.captchaId = result.data.sessionId;
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ const handleSendSmsCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendSmsCode(registerForm.phone!);
|
const result = await authApi.sendSmsCode(registerForm.phone!, 'register');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
registerForm.smsSessionId = result.data.sessionId;
|
registerForm.smsSessionId = result.data.sessionId;
|
||||||
@@ -421,7 +421,7 @@ const handleSendEmailCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendEmailCode(registerForm.email!);
|
const result = await authApi.sendEmailCode(registerForm.email!, 'register');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
registerForm.emailSessionId = result.data.sessionId;
|
registerForm.emailSessionId = result.data.sessionId;
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ const handleSendSmsCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendSmsCode(registerForm.phone!);
|
const result = await authApi.sendSmsCode(registerForm.phone!, 'register');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
registerForm.smsSessionId = result.data.sessionId;
|
registerForm.smsSessionId = result.data.sessionId;
|
||||||
@@ -432,7 +432,7 @@ const handleSendEmailCode = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await authApi.sendEmailCode(registerForm.email!);
|
const result = await authApi.sendEmailCode(registerForm.email!, 'register');
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
// 保存sessionId
|
// 保存sessionId
|
||||||
registerForm.emailSessionId = result.data.sessionId;
|
registerForm.emailSessionId = result.data.sessionId;
|
||||||
|
|||||||
Reference in New Issue
Block a user