refactor(auth): 重构登录认证和验证码功能

- 创建 SystemAuthVo 类用于统一登录返回数据结构
- 创建 SystemCaptchaVo 类用于验证码信息封装
- 将验证码功能从 SystemAuthService 拆分为独立的 SystemCaptchaService
- 登录接口返回类型从 Map 改为 SystemAuthVo
- 验证码接口返回类型从 Map 改为 SystemCaptchaVo
- 登录时验证码校验改为调用 SystemCaptchaService
- 移除 SystemAuthService 中的验证码相关代码
- 统一数据返回格式,提高代码可读性
This commit is contained in:
2026-01-08 09:25:31 +08:00
parent da6fe40960
commit 547421ad44
9 changed files with 214 additions and 55 deletions
@@ -0,0 +1,16 @@
package cn.odboy.system.dal.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
/**
* 登录成功后:token 与 用户信息
*/
@Getter
@Setter
public class SystemAuthVo extends KitObject {
private String token;
private SystemUserInfoVo user;
}
@@ -0,0 +1,22 @@
package cn.odboy.system.dal.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
/**
* 验证码信息
*/
@Getter
@Setter
public class SystemCaptchaVo extends KitObject {
/**
* redis key
*/
private String uuid;
/**
* image base64
*/
private String img;
}
@@ -0,0 +1,59 @@
package cn.odboy.system.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.constant.CaptchaCodeEnum;
import cn.odboy.constant.SystemConst;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.redis.KitRedisHelper;
import cn.odboy.system.dal.model.SystemCaptchaVo;
import cn.odboy.system.dal.redis.SystemCacheKey;
import com.wf.captcha.base.Captcha;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 验证码
*/
@Service
public class SystemCaptchaService {
@Autowired
private KitRedisHelper redisHelper;
@Autowired
private AppProperties properties;
public SystemCaptchaVo getLoginCaptcha() {
// 获取运算的结果
Captcha captcha = properties.getLogin().getCaptchaSetting().getCaptcha();
String uuid = SystemCacheKey.CAPTCHA_LOGIN + IdUtil.simpleUUID();
//当验证码类型为 arithmetic时且长度 >= 2 时, captcha.text()的结果有几率为浮点型
String captchaValue = captcha.text();
if (captcha.getCharType() - 1 == CaptchaCodeEnum.ARITHMETIC.ordinal() &&
captchaValue.contains(SystemConst.SYMBOL_DOT)) {
captchaValue = captchaValue.split("\\.")[0];
}
// 保存
redisHelper.set(uuid, captchaValue, properties.getLogin().getCaptchaSetting().getExpiration(), TimeUnit.MINUTES);
// 验证码信息
SystemCaptchaVo captchaVo = new SystemCaptchaVo();
captchaVo.setUuid(uuid);
captchaVo.setImg(captcha.toBase64());
return captchaVo;
}
public void validate(String uuid, String inputCode) {
// 查询验证码
String code = redisHelper.get(uuid, String.class);
if (StrUtil.isBlank(code)) {
throw new BadRequestException("验证码不存在或已过期");
}
// 清除验证码
redisHelper.del(uuid);
if (StrUtil.isBlank(inputCode) || !code.equalsIgnoreCase(inputCode)) {
throw new BadRequestException("验证码错误");
}
}
}
@@ -16,11 +16,11 @@
package cn.odboy.system.controller;
import cn.odboy.annotation.AnonymousPostMapping;
import cn.odboy.system.dal.model.SystemAuthVo;
import cn.odboy.system.dal.model.SystemUserLoginArgs;
import cn.odboy.system.service.SystemAuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -44,9 +44,8 @@ public class SystemAuthController {
@ApiOperation("登录授权")
@AnonymousPostMapping(value = "/login")
public ResponseEntity<Map<String, Object>> login(@Validated @RequestBody SystemUserLoginArgs loginRequest,
HttpServletRequest request) throws Exception {
Map<String, Object> loginInfo = systemAuthService.doLogin(loginRequest, request);
public ResponseEntity<SystemAuthVo> login(@Validated @RequestBody SystemUserLoginArgs loginRequest, HttpServletRequest request) throws Exception {
SystemAuthVo loginInfo = systemAuthService.doLogin(loginRequest, request);
return ResponseEntity.ok(loginInfo);
}
@@ -0,0 +1,16 @@
package cn.odboy.system.dal.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
/**
* 登录成功后:token 与 用户信息
*/
@Getter
@Setter
public class SystemAuthVo extends KitObject {
private String token;
private SystemUserInfoVo user;
}
@@ -0,0 +1,22 @@
package cn.odboy.system.dal.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
/**
* 验证码信息
*/
@Getter
@Setter
public class SystemCaptchaVo extends KitObject {
/**
* redis key
*/
private String uuid;
/**
* image base64
*/
private String img;
}
@@ -16,10 +16,10 @@
package cn.odboy.system.openapi;
import cn.odboy.annotation.AnonymousPostMapping;
import cn.odboy.system.service.SystemAuthService;
import cn.odboy.system.dal.model.SystemCaptchaVo;
import cn.odboy.system.service.SystemCaptchaService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -31,12 +31,12 @@ import org.springframework.web.bind.annotation.RestController;
public class SystemCaptchaOpenController {
@Autowired
private SystemAuthService systemAuthService;
private SystemCaptchaService systemCaptchaService;
@ApiOperation("获取验证码")
@AnonymousPostMapping(value = "/getCode")
public ResponseEntity<Map<String, Object>> getCode() {
Map<String, Object> imgResult = systemAuthService.getCaptchaInfo();
public ResponseEntity<SystemCaptchaVo> getCode() {
SystemCaptchaVo imgResult = systemCaptchaService.getLoginCaptcha();
return ResponseEntity.ok(imgResult);
}
}
@@ -1,26 +1,19 @@
package cn.odboy.system.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.constant.CaptchaCodeEnum;
import cn.odboy.constant.SystemConst;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.redis.KitRedisHelper;
import cn.odboy.system.dal.model.SystemAuthVo;
import cn.odboy.system.dal.model.SystemUserInfoVo;
import cn.odboy.system.dal.model.SystemUserJwtVo;
import cn.odboy.system.dal.model.SystemUserLoginArgs;
import cn.odboy.system.dal.redis.SystemCacheKey;
import cn.odboy.system.dal.redis.SystemUserOnlineInfoDAO;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.system.framework.permission.core.handler.TokenProvider;
import cn.odboy.system.framework.permission.core.handler.UserDetailsHandler;
import cn.odboy.util.KitBeanUtil;
import cn.odboy.util.KitRsaEncryptUtil;
import com.wf.captcha.base.Captcha;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -35,29 +28,23 @@ public class SystemAuthService {
@Autowired
private KitRedisHelper redisHelper;
@Autowired
private AppProperties properties;
@Autowired
private SystemUserOnlineInfoDAO systemUserOnlineInfoDAO;
@Autowired
private TokenProvider tokenProvider;
@Autowired
private AppProperties properties;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserDetailsHandler userDetailsService;
@Autowired
private SystemCaptchaService systemCaptchaService;
public Map<String, Object> doLogin(SystemUserLoginArgs loginRequest, HttpServletRequest request) throws Exception {
public SystemAuthVo doLogin(SystemUserLoginArgs loginRequest, HttpServletRequest request) throws Exception {
// 密码解密
String password = KitRsaEncryptUtil.decryptByPrivateKey(properties.getRsa().getPrivateKey(), loginRequest.getPassword());
// 查询验证码
String code = redisHelper.get(loginRequest.getUuid(), String.class);
// 清除验证码
redisHelper.del(loginRequest.getUuid());
if (StrUtil.isBlank(code)) {
throw new BadRequestException("验证码不存在或已过期");
}
if (StrUtil.isBlank(loginRequest.getCode()) || !loginRequest.getCode().equalsIgnoreCase(code)) {
throw new BadRequestException("验证码错误");
}
// 校验验证码
systemCaptchaService.validate(loginRequest.getUuid(), loginRequest.getCode());
// 获取用户信息
SystemUserJwtVo jwtUser = userDetailsService.loadUserByUsername(loginRequest.getUsername());
// 验证用户密码
@@ -69,11 +56,10 @@ public class SystemAuthService {
// 生成令牌
String token = tokenProvider.createToken(jwtUser);
// 返回 token 与 用户信息
Map<String, Object> authInfo = new HashMap<>(2) {{
put("token", String.format("%s %s", SystemConst.TOKEN_PREFIX, token));
// 这里是为了清空密码
put("user", KitBeanUtil.copyToClass(jwtUser, SystemUserInfoVo.class));
}};
SystemAuthVo authInfo = new SystemAuthVo();
authInfo.setToken(String.format("%s %s", SystemConst.TOKEN_PREFIX, token));
// 这里是为了清空密码
authInfo.setUser(KitBeanUtil.copyToClass(jwtUser, SystemUserInfoVo.class));
if (properties.getLogin().isSingle()) {
// 踢掉之前已经登录的token
systemUserOnlineInfoDAO.kickOutByUsername(loginRequest.getUsername());
@@ -92,26 +78,6 @@ public class SystemAuthService {
return jwtUser;
}
public Map<String, Object> getCaptchaInfo() {
// 获取运算的结果
Captcha captcha = properties.getLogin().getCaptchaSetting().getCaptcha();
String uuid = SystemCacheKey.CAPTCHA_LOGIN + IdUtil.simpleUUID();
//当验证码类型为 arithmetic时且长度 >= 2 时, captcha.text()的结果有几率为浮点型
String captchaValue = captcha.text();
if (captcha.getCharType() - 1 == CaptchaCodeEnum.ARITHMETIC.ordinal() &&
captchaValue.contains(SystemConst.SYMBOL_DOT)) {
captchaValue = captchaValue.split("\\.")[0];
}
// 保存
redisHelper.set(uuid, captchaValue, properties.getLogin().getCaptchaSetting().getExpiration(),
TimeUnit.MINUTES);
// 验证码信息
return new HashMap<>(2) {{
put("img", captcha.toBase64());
put("uuid", uuid);
}};
}
public void doLogout(HttpServletRequest request) {
String token = tokenProvider.getToken(request);
systemUserOnlineInfoDAO.logoutByToken(token);
@@ -0,0 +1,59 @@
package cn.odboy.system.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.constant.CaptchaCodeEnum;
import cn.odboy.constant.SystemConst;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.redis.KitRedisHelper;
import cn.odboy.system.dal.model.SystemCaptchaVo;
import cn.odboy.system.dal.redis.SystemCacheKey;
import com.wf.captcha.base.Captcha;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 验证码
*/
@Service
public class SystemCaptchaService {
@Autowired
private KitRedisHelper redisHelper;
@Autowired
private AppProperties properties;
public SystemCaptchaVo getLoginCaptcha() {
// 获取运算的结果
Captcha captcha = properties.getLogin().getCaptchaSetting().getCaptcha();
String uuid = SystemCacheKey.CAPTCHA_LOGIN + IdUtil.simpleUUID();
//当验证码类型为 arithmetic时且长度 >= 2 时, captcha.text()的结果有几率为浮点型
String captchaValue = captcha.text();
if (captcha.getCharType() - 1 == CaptchaCodeEnum.ARITHMETIC.ordinal() &&
captchaValue.contains(SystemConst.SYMBOL_DOT)) {
captchaValue = captchaValue.split("\\.")[0];
}
// 保存
redisHelper.set(uuid, captchaValue, properties.getLogin().getCaptchaSetting().getExpiration(), TimeUnit.MINUTES);
// 验证码信息
SystemCaptchaVo captchaVo = new SystemCaptchaVo();
captchaVo.setUuid(uuid);
captchaVo.setImg(captcha.toBase64());
return captchaVo;
}
public void validate(String uuid, String inputCode) {
// 查询验证码
String code = redisHelper.get(uuid, String.class);
if (StrUtil.isBlank(code)) {
throw new BadRequestException("验证码不存在或已过期");
}
// 清除验证码
redisHelper.del(uuid);
if (StrUtil.isBlank(inputCode) || !code.equalsIgnoreCase(inputCode)) {
throw new BadRequestException("验证码错误");
}
}
}