登录注册、手机号、邮箱
This commit is contained in:
@@ -1,14 +1,24 @@
|
||||
package org.xyzh.auth.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.xyzh.api.auth.login.LoginService;
|
||||
import org.xyzh.api.system.user.UserService;
|
||||
import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.common.utils.EmailUtils;
|
||||
import org.xyzh.common.utils.SmsUtils;
|
||||
import org.xyzh.common.redis.service.RedisService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description AuthController.java文件描述 认证控制器
|
||||
@@ -21,9 +31,25 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
|
||||
|
||||
@Autowired
|
||||
private LoginService loginService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private EmailUtils emailUtils;
|
||||
|
||||
@Autowired
|
||||
private SmsUtils smsUtils;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
/**
|
||||
* @description 用户登录
|
||||
* @param loginParam 登录参数
|
||||
@@ -99,4 +125,360 @@ public class AuthController {
|
||||
result.success("认证服务运行正常", "OK");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 发送邮箱验证码
|
||||
* @param requestBody 包含email字段的请求体
|
||||
* @return ResultDomain<Boolean> 发送结果
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
@PostMapping("/send-email-code")
|
||||
public ResultDomain<Map<String, String>> sendEmailCode(@RequestBody Map<String, String> requestBody) {
|
||||
ResultDomain<Map<String, String>> result = new ResultDomain<>();
|
||||
|
||||
String email = requestBody.get("email");
|
||||
|
||||
// 验证邮箱格式
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
result.fail("邮箱不能为空");
|
||||
return result;
|
||||
}
|
||||
|
||||
String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
|
||||
if (!email.matches(emailRegex)) {
|
||||
result.fail("邮箱格式不正确");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查是否频繁发送(60秒内只能发送一次)
|
||||
String rateLimitKey = "email:code:ratelimit:" + email;
|
||||
if (redisService.hasKey(rateLimitKey)) {
|
||||
result.fail("验证码已发送,请勿重复发送");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 生成会话ID(用于绑定验证码和用户)
|
||||
String sessionId = IDUtils.generateID();
|
||||
|
||||
// 生成6位数字验证码
|
||||
String code = EmailUtils.generateVerificationCode();
|
||||
|
||||
// 发送邮件
|
||||
boolean success = emailUtils.sendVerificationCode(email, code);
|
||||
|
||||
if (success) {
|
||||
// 将验证码存储到Redis,绑定sessionId,有效期5分钟
|
||||
String codeKey = "email:code:" + sessionId;
|
||||
String codeValue = email + ":" + code; // 格式:邮箱:验证码
|
||||
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
||||
|
||||
// 设置5分钟的发送频率限制
|
||||
redisService.set(rateLimitKey, "1", 5, TimeUnit.MINUTES);
|
||||
|
||||
// 返回sessionId给前端
|
||||
Map<String, String> data = Map.of(
|
||||
"sessionId", sessionId,
|
||||
"message", "验证码已发送到邮箱"
|
||||
);
|
||||
|
||||
logger.info("邮箱验证码已发送,邮箱: {}, sessionId: {}", email, sessionId);
|
||||
result.success("验证码已发送到邮箱", data);
|
||||
} else {
|
||||
result.fail("验证码发送失败,请稍后重试");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 发送手机验证码
|
||||
* @param requestBody 包含phone字段的请求体
|
||||
* @return ResultDomain<Boolean> 发送结果
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
@PostMapping("/send-sms-code")
|
||||
public ResultDomain<Map<String, String>> sendSmsCode(@RequestBody Map<String, String> requestBody) {
|
||||
ResultDomain<Map<String, String>> result = new ResultDomain<>();
|
||||
|
||||
String phone = requestBody.get("phone");
|
||||
|
||||
// 验证手机号格式
|
||||
if (phone == null || phone.trim().isEmpty()) {
|
||||
result.fail("手机号不能为空");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!SmsUtils.isValidPhone(phone)) {
|
||||
result.fail("手机号格式不正确");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查是否频繁发送(60秒内只能发送一次)
|
||||
String rateLimitKey = "sms:code:ratelimit:" + phone;
|
||||
if (redisService.hasKey(rateLimitKey)) {
|
||||
result.fail("验证码已发送,请勿重复发送");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 生成会话ID(用于绑定验证码和用户)
|
||||
String sessionId = IDUtils.generateID();
|
||||
|
||||
// 生成6位数字验证码
|
||||
String code = SmsUtils.generateVerificationCode();
|
||||
|
||||
// 发送短信
|
||||
boolean success = smsUtils.sendVerificationCode(phone, code);
|
||||
|
||||
if (success) {
|
||||
// 将验证码存储到Redis,绑定sessionId,有效期5分钟
|
||||
String codeKey = "sms:code:" + sessionId;
|
||||
String codeValue = phone + ":" + code; // 格式:手机号:验证码
|
||||
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
||||
|
||||
// 设置5分钟的发送频率限制
|
||||
redisService.set(rateLimitKey, "1", 5, TimeUnit.MINUTES);
|
||||
|
||||
// 返回sessionId给前端
|
||||
Map<String, String> data = Map.of(
|
||||
"sessionId", sessionId,
|
||||
"message", "验证码已发送"
|
||||
);
|
||||
|
||||
logger.info("短信验证码已发送,手机号: {}, sessionId: {}", phone, sessionId);
|
||||
result.success("验证码已发送", data);
|
||||
} else {
|
||||
result.fail("验证码发送失败,请稍后重试");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用户注册
|
||||
* @param requestBody 注册参数
|
||||
* @return ResultDomain<LoginDomain> 注册结果
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public ResultDomain<LoginDomain> register(@RequestBody Map<String, Object> requestBody, HttpServletRequest request) {
|
||||
ResultDomain<LoginDomain> result = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
// 获取注册参数
|
||||
String registerType = (String) requestBody.get("registerType");
|
||||
String username = (String) requestBody.get("username");
|
||||
String phone = (String) requestBody.get("phone");
|
||||
String email = (String) requestBody.get("email");
|
||||
String password = (String) requestBody.get("password");
|
||||
String confirmPassword = (String) requestBody.get("confirmPassword");
|
||||
String smsCode = (String) requestBody.get("smsCode");
|
||||
String emailCode = (String) requestBody.get("emailCode");
|
||||
String smsSessionId = (String) requestBody.get("smsSessionId");
|
||||
String emailSessionId = (String) requestBody.get("emailSessionId");
|
||||
String studentId = (String) requestBody.get("studentId");
|
||||
|
||||
// 1. 参数验证
|
||||
if (password == null || password.trim().isEmpty()) {
|
||||
result.fail("密码不能为空");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (password.length() < 6) {
|
||||
result.fail("密码至少6个字符");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!password.equals(confirmPassword)) {
|
||||
result.fail("两次输入的密码不一致");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 根据注册类型进行不同的验证
|
||||
TbSysUser user = new TbSysUser();
|
||||
|
||||
switch (registerType) {
|
||||
case "username":
|
||||
// 用户名注册
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
result.fail("用户名不能为空");
|
||||
return result;
|
||||
}
|
||||
if (username.length() < 3 || username.length() > 20) {
|
||||
result.fail("用户名长度为3-20个字符");
|
||||
return result;
|
||||
}
|
||||
if (!username.matches("^[a-zA-Z0-9_]+$")) {
|
||||
result.fail("用户名只能包含字母、数字和下划线");
|
||||
return result;
|
||||
}
|
||||
user.setUsername(username);
|
||||
logger.info("用户名注册: {}", username);
|
||||
break;
|
||||
|
||||
case "phone":
|
||||
// 手机号注册
|
||||
if (phone == null || phone.trim().isEmpty()) {
|
||||
result.fail("手机号不能为空");
|
||||
return result;
|
||||
}
|
||||
if (!phone.matches("^1[3-9]\\d{9}$")) {
|
||||
result.fail("手机号格式不正确");
|
||||
return result;
|
||||
}
|
||||
if (smsCode == null || smsCode.trim().isEmpty()) {
|
||||
result.fail("请输入手机验证码");
|
||||
return result;
|
||||
}
|
||||
if (smsSessionId == null || smsSessionId.trim().isEmpty()) {
|
||||
result.fail("会话已失效,请重新获取验证码");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 通过sessionId验证手机验证码
|
||||
String smsCodeKey = "sms:code:" + smsSessionId;
|
||||
String storedSmsValue = (String) redisService.get(smsCodeKey);
|
||||
if (storedSmsValue == null) {
|
||||
result.fail("验证码已过期,请重新获取");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 解析存储的值:手机号:验证码
|
||||
String[] smsParts = storedSmsValue.split(":");
|
||||
if (smsParts.length != 2) {
|
||||
result.fail("验证码数据异常");
|
||||
return result;
|
||||
}
|
||||
|
||||
String storedPhone = smsParts[0];
|
||||
String storedSmsCode = smsParts[1];
|
||||
|
||||
// 验证手机号和验证码是否匹配
|
||||
if (!storedPhone.equals(phone)) {
|
||||
result.fail("手机号与验证码不匹配");
|
||||
logger.warn("手机号注册验证失败,提交手机号: {}, 验证码绑定手机号: {}", phone, storedPhone);
|
||||
return result;
|
||||
}
|
||||
if (!storedSmsCode.equals(smsCode)) {
|
||||
result.fail("验证码错误");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 验证码使用后删除
|
||||
redisService.delete(smsCodeKey);
|
||||
|
||||
user.setPhone(phone);
|
||||
user.setUsername(phone); // 使用手机号作为用户名
|
||||
logger.info("手机号注册: {}, sessionId: {}", phone, smsSessionId);
|
||||
break;
|
||||
|
||||
case "email":
|
||||
// 邮箱注册
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
result.fail("邮箱不能为空");
|
||||
return result;
|
||||
}
|
||||
if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
|
||||
result.fail("邮箱格式不正确");
|
||||
return result;
|
||||
}
|
||||
if (emailCode == null || emailCode.trim().isEmpty()) {
|
||||
result.fail("请输入邮箱验证码");
|
||||
return result;
|
||||
}
|
||||
if (emailSessionId == null || emailSessionId.trim().isEmpty()) {
|
||||
result.fail("会话已失效,请重新获取验证码");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 通过sessionId验证邮箱验证码
|
||||
String emailCodeKey = "email:code:" + emailSessionId;
|
||||
String storedEmailValue = (String) redisService.get(emailCodeKey);
|
||||
if (storedEmailValue == null) {
|
||||
result.fail("验证码已过期,请重新获取");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 解析存储的值:邮箱:验证码
|
||||
String[] emailParts = storedEmailValue.split(":");
|
||||
if (emailParts.length != 2) {
|
||||
result.fail("验证码数据异常");
|
||||
return result;
|
||||
}
|
||||
|
||||
String storedEmail = emailParts[0];
|
||||
String storedEmailCode = emailParts[1];
|
||||
|
||||
// 验证邮箱和验证码是否匹配
|
||||
if (!storedEmail.equals(email)) {
|
||||
result.fail("邮箱与验证码不匹配");
|
||||
logger.warn("邮箱注册验证失败,提交邮箱: {}, 验证码绑定邮箱: {}", email, storedEmail);
|
||||
return result;
|
||||
}
|
||||
if (!storedEmailCode.equals(emailCode)) {
|
||||
result.fail("验证码错误");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 验证码使用后删除
|
||||
redisService.delete(emailCodeKey);
|
||||
|
||||
user.setEmail(email);
|
||||
user.setUsername(email.split("@")[0]); // 使用邮箱前缀作为用户名
|
||||
logger.info("邮箱注册: {}, sessionId: {}", email, emailSessionId);
|
||||
break;
|
||||
|
||||
default:
|
||||
result.fail("未知的注册类型");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. 密码加密
|
||||
String encryptedPassword = passwordEncoder.encode(password);
|
||||
user.setPassword(encryptedPassword);
|
||||
|
||||
// 4. 设置用户状态为正常
|
||||
user.setStatus(0);
|
||||
|
||||
// 5. 调用UserService注册用户
|
||||
ResultDomain<TbSysUser> registerResult = userService.registerUser(user);
|
||||
|
||||
if (!registerResult.isSuccess()) {
|
||||
result.fail(registerResult.getMessage());
|
||||
return result;
|
||||
}
|
||||
|
||||
logger.info("用户注册成功: {}", user.getUsername());
|
||||
|
||||
// 6. 注册成功后自动登录
|
||||
LoginParam loginParam = new LoginParam();
|
||||
loginParam.setUsername(user.getUsername());
|
||||
loginParam.setPassword(password);
|
||||
loginParam.setLoginType("password");
|
||||
|
||||
if (phone != null && !phone.trim().isEmpty()) {
|
||||
loginParam.setPhone(phone);
|
||||
}
|
||||
if (email != null && !email.trim().isEmpty()) {
|
||||
loginParam.setEmail(email);
|
||||
}
|
||||
|
||||
ResultDomain<LoginDomain> loginResult = loginService.login(loginParam, request);
|
||||
|
||||
if (loginResult.isSuccess()) {
|
||||
result.success("注册成功", loginResult.getData());
|
||||
} else {
|
||||
// 注册成功但登录失败,返回注册成功信息
|
||||
result.success("注册成功,请登录", loginResult.getData());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("用户注册失败", e);
|
||||
result.fail("注册失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,23 +118,17 @@ public class LoginServiceImpl implements LoginService {
|
||||
}
|
||||
|
||||
if (loginType.equals("password")) {
|
||||
// 验证凭据(密码或验证码)
|
||||
if (!strategy.verifyCredential(loginParam.getPassword(), user.getPassword())) {
|
||||
result.fail("密码错误");
|
||||
logLoginAttempt(loginParam, user, false, loginAttempt, "密码错误");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 验证凭据(验证码)
|
||||
String storedCaptcha = (String) redisService.get("captcha:" + loginParam.getPhone());
|
||||
if (!strategy.verifyCredential(loginParam.getCaptcha(), storedCaptcha)) {
|
||||
result.fail("验证码错误");
|
||||
logLoginAttempt(loginParam, user, false, loginAttempt, "验证码错误");
|
||||
} else if (loginType.equals("email") || loginType.equals("phone")) {
|
||||
if (!strategy.verifyCaptchaWithSession(loginParam)) {
|
||||
result.fail("验证码错误或已过期");
|
||||
logLoginAttempt(loginParam, user, false, loginAttempt, "验证码验证失败");
|
||||
return result;
|
||||
}
|
||||
// 验证码使用后删除
|
||||
redisService.delete("captcha:" + loginParam.getPhone());
|
||||
}
|
||||
|
||||
// 构建登录域对象
|
||||
@@ -142,9 +136,12 @@ public class LoginServiceImpl implements LoginService {
|
||||
// 生成JWT令牌
|
||||
loginDomain.setToken(jwtTokenUtil.generateToken(loginDomain));
|
||||
|
||||
// 将LoginDomain存储到Redis中
|
||||
// 将LoginDomain存储到Redis中,根据rememberMe设置不同的过期时间
|
||||
String redisKey = "login:token:" + user.getID();
|
||||
redisService.set(redisKey, loginDomain, 24 * 60 * 60, TimeUnit.SECONDS);
|
||||
long expireTime = loginParam.isRememberMe()
|
||||
? 7 * 24 * 60 * 60 // rememberMe: 7天
|
||||
: 24 * 60 * 60; // 不rememberMe: 1天
|
||||
redisService.set(redisKey, loginDomain, expireTime, TimeUnit.SECONDS);
|
||||
|
||||
// 登录成功后清除失败次数并记录成功日志
|
||||
redisService.delete(attemptKey);
|
||||
@@ -280,6 +277,16 @@ public class LoginServiceImpl implements LoginService {
|
||||
if (user != null) {
|
||||
loginLog.setUserID(user.getID());
|
||||
loginLog.setUsername(user.getUsername());
|
||||
}else{
|
||||
if (loginParam.getLoginType().equals("password")) {
|
||||
loginLog.setUsername(loginParam.getUsername());
|
||||
}else if (loginParam.getLoginType().equals("email")) {
|
||||
loginLog.setUsername(loginParam.getEmail());
|
||||
}else if (loginParam.getLoginType().equals("phone")) {
|
||||
loginLog.setUsername(loginParam.getPhone());
|
||||
}else if (loginParam.getLoginType().equals("wechat")) {
|
||||
loginLog.setUsername(loginParam.getWechatID());
|
||||
}
|
||||
}
|
||||
// 注意:实际生产中不应记录密码
|
||||
// loginLog.setPassword(loginParam.getPassword());
|
||||
|
||||
@@ -47,4 +47,16 @@ public interface LoginStrategy {
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
boolean verifyCredential(String inputCredential, String storedCredential);
|
||||
|
||||
/**
|
||||
* @description 验证验证码(从Redis获取并验证SessionID)
|
||||
* @param loginParam 登录参数
|
||||
* @return boolean 是否验证成功
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
default boolean verifyCaptchaWithSession(LoginParam loginParam) {
|
||||
// 默认实现:不支持验证码登录
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,12 @@ package org.xyzh.auth.strategy.impl;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.xyzh.auth.strategy.LoginStrategy;
|
||||
import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.api.system.user.UserService;
|
||||
import org.xyzh.common.redis.service.RedisService;
|
||||
|
||||
/**
|
||||
* @description EmailLoginStrategy.java文件描述 邮箱登录策略
|
||||
@@ -34,23 +32,72 @@ public class EmailLoginStrategy implements LoginStrategy {
|
||||
|
||||
@Override
|
||||
public boolean validate(LoginParam loginParam) {
|
||||
return loginParam.getEmail() != null && !loginParam.getEmail().trim().isEmpty()
|
||||
&& loginParam.getPassword() != null && !loginParam.getPassword().trim().isEmpty();
|
||||
if (loginParam.getEmail() == null || loginParam.getEmail().trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 密码登录或验证码登录都可以
|
||||
return (loginParam.getPassword() != null && !loginParam.getPassword().trim().isEmpty())
|
||||
|| (loginParam.getCaptcha() != null && !loginParam.getCaptcha().trim().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbSysUser findUser(LoginParam loginParam) {
|
||||
TbSysUser filter = new TbSysUser();
|
||||
filter.setEmail(loginParam.getEmail());
|
||||
List<TbSysUser> users = userService.getUserByFilter(filter).getDataList();
|
||||
if(users.isEmpty()) {
|
||||
TbSysUser user = userService.getLoginUser(filter).getData();
|
||||
if(user == null) {
|
||||
return null;
|
||||
}
|
||||
return users.get(0);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public boolean verifyCredential(String inputCredential, String storedCredential) {
|
||||
// 密码验证
|
||||
return passwordEncoder.matches(inputCredential, storedCredential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyCaptchaWithSession(LoginParam loginParam) {
|
||||
String captchaId = loginParam.getCaptchaId();
|
||||
String inputCaptcha = loginParam.getCaptcha();
|
||||
String email = loginParam.getEmail();
|
||||
|
||||
// 验证参数
|
||||
if (captchaId == null || captchaId.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (inputCaptcha == null || inputCaptcha.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从Redis获取验证码
|
||||
String codeKey = "email:code:" + captchaId;
|
||||
String storedValue = (String) redisService.get(codeKey);
|
||||
|
||||
if (storedValue == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析存储的值:邮箱:验证码
|
||||
String[] parts = storedValue.split(":");
|
||||
if (parts.length != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String storedEmail = parts[0];
|
||||
String storedCaptcha = parts[1];
|
||||
|
||||
// 验证邮箱和验证码是否匹配
|
||||
if (!storedEmail.equals(email) || !storedCaptcha.equals(inputCaptcha)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证码使用后删除
|
||||
redisService.delete(codeKey);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import org.xyzh.auth.strategy.LoginStrategy;
|
||||
import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.common.utils.NonUtils;
|
||||
import org.xyzh.common.utils.validation.ValidationUtils;
|
||||
import org.xyzh.common.utils.validation.method.EmailValidateMethod;
|
||||
import org.xyzh.common.utils.validation.method.PhoneValidateMethod;
|
||||
import org.xyzh.api.system.user.UserService;
|
||||
|
||||
import java.util.List;
|
||||
@@ -53,15 +56,15 @@ public class PasswordLoginStrategy implements LoginStrategy {
|
||||
@Override
|
||||
public TbSysUser findUser(LoginParam loginParam) {
|
||||
TbSysUser filter = new TbSysUser();
|
||||
if (NonUtils.isNotEmpty(loginParam.getUsername())) {
|
||||
EmailValidateMethod emailValidateMethod = new EmailValidateMethod();
|
||||
PhoneValidateMethod phoneValidateMethod = new PhoneValidateMethod();
|
||||
if(emailValidateMethod.validate(loginParam.getUsername())){
|
||||
filter.setEmail(loginParam.getUsername());
|
||||
}else if (phoneValidateMethod.validate(loginParam.getUsername())){
|
||||
filter.setPhone(loginParam.getUsername());
|
||||
}else{
|
||||
filter.setUsername(loginParam.getUsername());
|
||||
}
|
||||
if (NonUtils.isNotEmpty(loginParam.getEmail())) {
|
||||
filter.setEmail(loginParam.getEmail());
|
||||
}
|
||||
if (NonUtils.isNotEmpty(loginParam.getPhone())) {
|
||||
filter.setPhone(loginParam.getPhone());
|
||||
}
|
||||
filter.setPassword(passwordEncoder.encode(loginParam.getPassword()));
|
||||
TbSysUser user = userService.getLoginUser(filter).getData();
|
||||
if(user == null) {
|
||||
|
||||
@@ -7,8 +7,7 @@ import org.xyzh.auth.strategy.LoginStrategy;
|
||||
import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.api.system.user.UserService;
|
||||
|
||||
import java.util.List;
|
||||
import org.xyzh.common.redis.service.RedisService;
|
||||
|
||||
/**
|
||||
* @description PhoneLoginStrategy.java文件描述 手机号登录策略
|
||||
@@ -33,27 +32,72 @@ public class PhoneLoginStrategy implements LoginStrategy {
|
||||
|
||||
@Override
|
||||
public boolean validate(LoginParam loginParam) {
|
||||
return loginParam.getPhone() != null && !loginParam.getPhone().trim().isEmpty()
|
||||
&& (loginParam.getPassword() != null || loginParam.getCaptcha() != null);
|
||||
if (loginParam.getPhone() == null || loginParam.getPhone().trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 密码登录或验证码登录都可以
|
||||
return (loginParam.getPassword() != null && !loginParam.getPassword().trim().isEmpty())
|
||||
|| (loginParam.getCaptcha() != null && !loginParam.getCaptcha().trim().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbSysUser findUser(LoginParam loginParam) {
|
||||
TbSysUser filter = new TbSysUser();
|
||||
filter.setPhone(loginParam.getPhone());
|
||||
List<TbSysUser> users = userService.getUserByFilter(filter).getDataList();
|
||||
if(users.isEmpty()) {
|
||||
TbSysUser user = userService.getLoginUser(filter).getData();
|
||||
if(user == null) {
|
||||
return null;
|
||||
}
|
||||
return users.get(0);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public boolean verifyCredential(String inputCredential, String storedCredential) {
|
||||
// 手机号登录可能使用验证码,如果有验证码则跳过密码验证
|
||||
if (inputCredential == null) {
|
||||
return true; // 假设验证码已经在其他地方验证过了
|
||||
}
|
||||
// 密码验证
|
||||
return passwordEncoder.matches(inputCredential, storedCredential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyCaptchaWithSession(LoginParam loginParam) {
|
||||
String captchaId = loginParam.getCaptchaId();
|
||||
String inputCaptcha = loginParam.getCaptcha();
|
||||
String phone = loginParam.getPhone();
|
||||
|
||||
// 验证参数
|
||||
if (captchaId == null || captchaId.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (inputCaptcha == null || inputCaptcha.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从Redis获取验证码
|
||||
String codeKey = "sms:code:" + captchaId;
|
||||
String storedValue = (String) redisService.get(codeKey);
|
||||
|
||||
if (storedValue == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析存储的值:手机号:验证码
|
||||
String[] parts = storedValue.split(":");
|
||||
if (parts.length != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String storedPhone = parts[0];
|
||||
String storedCaptcha = parts[1];
|
||||
|
||||
// 验证手机号和验证码是否匹配
|
||||
if (!storedPhone.equals(phone) || !storedCaptcha.equals(inputCaptcha)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证码使用后删除
|
||||
redisService.delete(codeKey);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.api.system.user.UserService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description UsernameLoginStrategy.java文件描述 用户名登录策略
|
||||
* @filename UsernameLoginStrategy.java
|
||||
@@ -41,11 +39,11 @@ public class UsernameLoginStrategy implements LoginStrategy {
|
||||
public TbSysUser findUser(LoginParam loginParam) {
|
||||
TbSysUser filter = new TbSysUser();
|
||||
filter.setUsername(loginParam.getUsername());
|
||||
List<TbSysUser> users = userService.getUserByFilter(filter).getDataList();
|
||||
if(users.isEmpty()) {
|
||||
TbSysUser user = userService.getLoginUser(filter).getData();
|
||||
if(user == null) {
|
||||
return null;
|
||||
}
|
||||
return users.get(0);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,8 +7,6 @@ import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.api.system.user.UserService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description WechatLoginStrategy.java文件描述 微信登录策略
|
||||
* @filename WechatLoginStrategy.java
|
||||
@@ -37,11 +35,11 @@ public class WechatLoginStrategy implements LoginStrategy {
|
||||
public TbSysUser findUser(LoginParam loginParam) {
|
||||
TbSysUser filter = new TbSysUser();
|
||||
filter.setWechatID(loginParam.getWechatID());
|
||||
List<TbSysUser> users = userService.getUserByFilter(filter).getDataList();
|
||||
if(users.isEmpty()) {
|
||||
TbSysUser user = userService.getLoginUser(filter).getData();
|
||||
if(user == null) {
|
||||
return null;
|
||||
}
|
||||
return users.get(0);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user