From c90e80e9d72eba173df586e7f12a0c9378c82ec9 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Fri, 27 Dec 2024 00:20:36 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E5=8F=8A=E5=AE=A2=E6=88=B7=E7=AB=AF=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/common/constant/SysConstants.java | 4 +- .../admin/common/context/UserContext.java | 4 +- .../{handler => }/AbstractAuthHandler.java | 118 ++++---- .../top/continew/admin/auth/AuthHandler.java | 51 ++-- ...hHandlerContext.java => AuthStrategy.java} | 35 +-- .../admin/auth/enums/AuthTypeEnum.java | 15 +- .../auth/handler/AccountAuthHandler.java | 138 ++++----- .../admin/auth/handler/EmailAuthHandler.java | 88 ++---- .../admin/auth/handler/PhoneAuthHandler.java | 90 ++---- .../admin/auth/handler/SocialAuthHandler.java | 113 ++++---- .../admin/auth/model/req/AccountAuthReq.java | 7 +- .../admin/auth/model/req/AuthReq.java | 35 ++- .../admin/auth/model/req/EmailAuthReq.java | 7 +- .../admin/auth/model/req/PhoneAuthReq.java | 7 +- .../admin/auth/model/req/SocialAuthReq.java | 22 +- .../admin/auth/model/resp/LoginResp.java | 4 +- .../{LoginService.java => AuthService.java} | 48 +--- .../auth/service/impl/AuthServiceImpl.java | 125 ++++++++ .../auth/service/impl/LoginServiceImpl.java | 267 ------------------ .../admin/system/mapper/ClientMapper.java | 4 +- .../admin/system/model/entity/ClientDO.java | 8 +- .../admin/system/model/query/ClientQuery.java | 19 +- .../admin/system/model/req/ClientReq.java | 18 +- .../system/model/resp/ClientDetailResp.java | 25 +- .../admin/system/model/resp/ClientResp.java | 6 +- .../admin/system/service/ClientService.java | 14 +- .../service/impl/ClientServiceImpl.java | 43 ++- .../admin/config/log/LogDaoLocalImpl.java | 8 +- .../admin/controller/auth/AuthController.java | 46 +-- .../controller/auth/SocialAuthController.java | 28 +- .../controller/system/ClientController.java | 6 +- .../db/changelog/mysql/main_data.sql | 47 ++- .../db/changelog/mysql/main_table.sql | 8 +- .../db/changelog/postgresql/main_data.sql | 2 +- .../db/changelog/postgresql/main_table.sql | 2 +- 35 files changed, 595 insertions(+), 867 deletions(-) rename continew-module-system/src/main/java/top/continew/admin/auth/{handler => }/AbstractAuthHandler.java (52%) rename continew-module-system/src/main/java/top/continew/admin/auth/{config/AuthHandlerContext.java => AuthStrategy.java} (54%) rename continew-module-system/src/main/java/top/continew/admin/auth/service/{LoginService.java => AuthService.java} (53%) create mode 100644 continew-module-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java delete mode 100644 continew-module-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java diff --git a/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java b/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java index 2e9ad5c3..509be74d 100644 --- a/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java +++ b/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java @@ -65,12 +65,12 @@ public class SysConstants { public static final String ALL_PERMISSION = "*:*:*"; /** - * 账号登录 URI + * 登录 URI */ public static final String LOGIN_URI = "/auth/login"; /** - * 退出 URI + * 登出 URI */ public static final String LOGOUT_URI = "/auth/logout"; diff --git a/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java b/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java index 4495a8c3..35223f4d 100644 --- a/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java +++ b/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java @@ -81,12 +81,12 @@ public class UserContext implements Serializable { private Set roles; /** - * 设备类型 + * 客户端类型 */ private String clientType; /** - * 客户端ID + * 客户端 ID */ private String clientId; diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/handler/AbstractAuthHandler.java b/continew-module-system/src/main/java/top/continew/admin/auth/AbstractAuthHandler.java similarity index 52% rename from continew-module-system/src/main/java/top/continew/admin/auth/handler/AbstractAuthHandler.java rename to continew-module-system/src/main/java/top/continew/admin/auth/AbstractAuthHandler.java index cd7c46e9..50d33ab3 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/handler/AbstractAuthHandler.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/AbstractAuthHandler.java @@ -14,23 +14,30 @@ * limitations under the License. */ -package top.continew.admin.auth.handler; +package top.continew.admin.auth; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import jakarta.annotation.Resource; -import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; +import top.continew.admin.auth.model.req.AuthReq; import top.continew.admin.common.context.RoleContext; import top.continew.admin.common.context.UserContext; import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.context.UserExtraContext; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.system.model.entity.DeptDO; import top.continew.admin.system.model.entity.UserDO; import top.continew.admin.system.model.resp.ClientResp; +import top.continew.admin.system.service.DeptService; import top.continew.admin.system.service.OptionService; import top.continew.admin.system.service.RoleService; +import top.continew.admin.system.service.UserService; +import top.continew.starter.core.validation.CheckUtils; +import top.continew.starter.core.validation.ValidationUtils; import top.continew.starter.web.util.SpringWebUtils; import java.util.Set; @@ -39,35 +46,49 @@ import java.util.concurrent.CompletableFuture; import static top.continew.admin.system.enums.PasswordPolicyEnum.PASSWORD_EXPIRATION_DAYS; /** - * 认证处理器抽象类 + * 认证处理器基类 * * @author KAI + * @author Charles7c * @since 2024/12/22 14:52 */ @Component -@RequiredArgsConstructor -public abstract class AbstractAuthHandler { +public abstract class AbstractAuthHandler implements AuthHandler { + @Resource - private RoleService roleService; + protected OptionService optionService; @Resource - private OptionService optionService; + protected UserService userService; + @Resource + protected RoleService roleService; + @Resource + private DeptService deptService; @Resource private ThreadPoolTaskExecutor threadPoolTaskExecutor; - public static final String CAPTCHA_EXPIRED = "验证码已失效"; - public static final String CAPTCHA_ERROR = "验证码错误"; - public static final String CLIENT_ID = "clientId"; + protected static final String CAPTCHA_EXPIRED = "验证码已失效"; + protected static final String CAPTCHA_ERROR = "验证码错误"; + protected static final String CLIENT_ID = "clientId"; + + @Override + public void preLogin(T req, ClientResp client, HttpServletRequest request) { + // 参数校验 + ValidationUtils.validate(req); + } + + @Override + public void postLogin(T req, ClientResp client, HttpServletRequest request) { + } /** - * 获取登录凭证 + * 认证 * - * @param user 用户信息 - * @param clientResp 客户端信息 - * @return token 认证信息 + * @param user 用户信息 + * @param client 客户端信息 + * @return token 令牌信息 */ - protected String authCertificate(UserDO user, ClientResp clientResp) { - preLogin(user, clientResp); - // 核心登录逻辑 + protected String authenticate(UserDO user, ClientResp client) { + // 获取权限、角色、密码过期天数 Long userId = user.getId(); CompletableFuture> permissionFuture = CompletableFuture.supplyAsync(() -> roleService .listPermissionByUserId(userId), threadPoolTaskExecutor); @@ -76,62 +97,35 @@ public abstract class AbstractAuthHandler { CompletableFuture passwordExpirationDaysFuture = CompletableFuture.supplyAsync(() -> optionService .getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name())); CompletableFuture.allOf(permissionFuture, roleFuture, passwordExpirationDaysFuture); - UserContext userContext = new UserContext(permissionFuture.join(), roleFuture .join(), passwordExpirationDaysFuture.join()); - BeanUtil.copyProperties(user, userContext); - SaLoginModel model = new SaLoginModel(); - // 设置登录 token 最低活跃频率 如未指定,则使用全局配置的 activeTimeout 值 - model.setActiveTimeout(clientResp.getActiveTimeout()); - // 设置登录 token 有效期,单位:秒 (如未指定,自动取全局配置的 timeout 值 - model.setTimeout(clientResp.getTimeout()); - // 设置设备类型 - model.setDevice(clientResp.getClientType()); - userContext.setClientType(clientResp.getClientType()); - // 设置客户端id - userContext.setClientId(clientResp.getClientId()); - model.setExtra(CLIENT_ID, clientResp.getClientId()); - // 自定义用户上下文处理 - customizeUserContext(userContext, user, clientResp); - // 登录并缓存用户信息 + SaLoginModel model = new SaLoginModel(); + // 指定此次登录 token 最低活跃频率,单位:秒(如未指定,则使用全局配置的 activeTimeout 值) + model.setActiveTimeout(client.getActiveTimeout()); + // 指定此次登录 token 有效期,单位:秒 (如未指定,自动取全局配置的 timeout 值) + model.setTimeout(client.getTimeout()); + // 客户端类型 + model.setDevice(client.getClientType()); + userContext.setClientType(client.getClientType()); + // 客户端 ID + model.setExtra(CLIENT_ID, client.getClientId()); + userContext.setClientId(client.getClientId()); StpUtil.login(userContext.getId(), model.setExtraData(BeanUtil.beanToMap(new UserExtraContext(SpringWebUtils .getRequest())))); UserContextHolder.setContext(userContext); - - // 后置处理 - String token = StpUtil.getTokenValue(); - postLogin(token, user, clientResp); - return token; + return StpUtil.getTokenValue(); } /** - * 登录前置处理 + * 检查用户状态 * - * @param user 用户信息 - * @param clientResp 客户端信息 + * @param user 用户信息 */ - private void preLogin(UserDO user, ClientResp clientResp) { - } - - /** - * 自定义用户上下文处理 - * - * @param userContext 用户上下文 - * @param user 用户信息 - * @param clientResp 客户端信息 - */ - protected void customizeUserContext(UserContext userContext, UserDO user, ClientResp clientResp) { - } - - /** - * 登录后置处理 - * - * @param token 登录令牌 - * @param user 用户信息 - * @param clientResp 客户端信息 - */ - protected void postLogin(String token, UserDO user, ClientResp clientResp) { + protected void checkUserStatus(UserDO user) { + CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, user.getStatus(), "此账号已被禁用,如有疑问,请联系管理员"); + DeptDO dept = deptService.getById(user.getDeptId()); + CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, dept.getStatus(), "此账号所属部门已被禁用,如有疑问,请联系管理员"); } } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/AuthHandler.java b/continew-module-system/src/main/java/top/continew/admin/auth/AuthHandler.java index e46e3a50..91de2a37 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/AuthHandler.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/AuthHandler.java @@ -19,37 +19,52 @@ package top.continew.admin.auth; import jakarta.servlet.http.HttpServletRequest; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.AuthReq; +import top.continew.admin.auth.model.resp.LoginResp; import top.continew.admin.system.model.resp.ClientResp; /** - * 认证接口 + * 认证处理器 * * @author KAI - * @since 2024/12/22 14:52:23 + * @author Charles7c + * @since 2024/12/22 14:52 */ -public interface AuthHandler { +public interface AuthHandler { /** - * 执行登录 + * 登录 * - * @param authReq 登录请求参数 - * @param request HTTP请求对象 - * @return 登录响应 + * @param req 登录请求参数 + * @param client 客户端信息 + * @param request 请求对象 + * @return 登录响应参数 */ - R login(T authReq, ClientResp clientResp, HttpServletRequest request); + LoginResp login(T req, ClientResp client, HttpServletRequest request); /** - * 获取登录类型 + * 登录前置处理 * - * @return 登录类型Enum + * + * @param req 登录请求参数 + * @param client 客户端信息 + * @param request 请求对象 + */ + void preLogin(T req, ClientResp client, HttpServletRequest request); + + /** + * 登录后置处理 + * + * + * @param req 登录请求参数 + * @param client 客户端信息 + * @param request 请求对象 + */ + void postLogin(T req, ClientResp client, HttpServletRequest request); + + /** + * 获取认证类型 + * + * @return 认证类型 */ AuthTypeEnum getAuthType(); - - /** - * 校验参数 - * - * @param authReq 登录请求参数 - */ - void validate(T authReq); - } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/config/AuthHandlerContext.java b/continew-module-system/src/main/java/top/continew/admin/auth/AuthStrategy.java similarity index 54% rename from continew-module-system/src/main/java/top/continew/admin/auth/config/AuthHandlerContext.java rename to continew-module-system/src/main/java/top/continew/admin/auth/AuthStrategy.java index f958de5f..bc31b3b4 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/config/AuthHandlerContext.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/AuthStrategy.java @@ -14,40 +14,43 @@ * limitations under the License. */ -package top.continew.admin.auth.config; +package top.continew.admin.auth; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.AuthReq; -import top.continew.admin.auth.AuthHandler; import java.util.HashMap; import java.util.List; import java.util.Map; /** - * 登录类型策略上文 + * 认证策略 * * @author KAI - * @since 2024/12/20 15:16:55 + * @author Charles7c + * @since 2024/12/20 15:16 */ @Component -public class AuthHandlerContext { - private final Map> handlerMap = new HashMap<>(); +public class AuthStrategy { + + private final Map> handlerMap = new HashMap<>(); @Autowired - public AuthHandlerContext(List> strategies) { - for (AuthHandler strategy : strategies) { - handlerMap.put(strategy.getAuthType().getValue(), strategy); + public AuthStrategy(List> handlers) { + for (AuthHandler handler : handlers) { + handlerMap.put(handler.getAuthType(), handler); } } - @SuppressWarnings("unchecked") - public AuthHandler getHandler(String type) { - AuthHandler strategy = handlerMap.get(type); - if (strategy == null) { - throw new IllegalArgumentException("No handler found for type: " + type); - } - return (AuthHandler)strategy; + /** + * 根据认证类型获取 + * + * @param authType 认证类型 + * @return 认证处理器 + */ + public AuthHandler getHandler(AuthTypeEnum authType) { + return (AuthHandler)handlerMap.get(authType); } } diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/enums/AuthTypeEnum.java b/continew-module-system/src/main/java/top/continew/admin/auth/enums/AuthTypeEnum.java index 92edad69..63846293 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/enums/AuthTypeEnum.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/enums/AuthTypeEnum.java @@ -22,10 +22,11 @@ import top.continew.admin.common.constant.UiConstants; import top.continew.starter.core.enums.BaseEnum; /** - * 认证类型 + * 认证类型枚举 * + * @author KAI * @author Charles7c - * @since 2023/12/23 13:38 + * @since 2024/12/22 14:52 */ @Getter @RequiredArgsConstructor @@ -34,22 +35,22 @@ public enum AuthTypeEnum implements BaseEnum { /** * 账号 */ - ACCOUNT("account", "账号", UiConstants.COLOR_ERROR), + ACCOUNT("ACCOUNT", "账号", UiConstants.COLOR_SUCCESS), /** * 邮箱 */ - EMAIL("email", "邮箱", UiConstants.COLOR_PRIMARY), + EMAIL("EMAIL", "邮箱", UiConstants.COLOR_PRIMARY), /** * 手机号 */ - PHONE("phone", "手机号", UiConstants.COLOR_SUCCESS), + PHONE("PHONE", "手机号", UiConstants.COLOR_PRIMARY), /** - * 第三方授权 + * 第三方账号 */ - SOCIAL_AUTH("socialAuth", "第三方授权", UiConstants.COLOR_DEFAULT); + SOCIAL("SOCIAL", "第三方账号", UiConstants.COLOR_ERROR); private final String value; private final String description; diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/handler/AccountAuthHandler.java b/continew-module-system/src/main/java/top/continew/admin/auth/handler/AccountAuthHandler.java index ebfefc2b..053344fd 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/handler/AccountAuthHandler.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/handler/AccountAuthHandler.java @@ -16,105 +16,109 @@ package top.continew.admin.auth.handler; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; +import top.continew.admin.auth.AbstractAuthHandler; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.AccountAuthReq; import top.continew.admin.auth.model.resp.LoginResp; -import top.continew.admin.auth.service.LoginService; -import top.continew.admin.auth.AuthHandler; +import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.SysConstants; import top.continew.admin.common.util.SecureUtils; +import top.continew.admin.system.enums.PasswordPolicyEnum; import top.continew.admin.system.model.entity.UserDO; import top.continew.admin.system.model.resp.ClientResp; -import top.continew.admin.system.service.OptionService; -import top.continew.admin.system.service.UserService; +import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.core.util.ExceptionUtils; +import top.continew.starter.core.validation.CheckUtils; import top.continew.starter.core.validation.ValidationUtils; +import java.time.Duration; + /** * 账号认证处理器 * * @author KAI - * @since 2024/12/22 14:58:32 + * @author Charles7c + * @since 2024/12/22 14:58 */ @Component @RequiredArgsConstructor -public class AccountAuthHandler extends AbstractAuthHandler implements AuthHandler { +public class AccountAuthHandler extends AbstractAuthHandler { - private final UserService userService; - private final LoginService loginService; private final PasswordEncoder passwordEncoder; - private final OptionService optionService; - /** - * 获取认证类型 - * - * @return 账号认证类型 - */ + @Override + public LoginResp login(AccountAuthReq req, ClientResp client, HttpServletRequest request) { + // 解密密码 + String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword())); + ValidationUtils.throwIfBlank(rawPassword, "密码解密失败"); + // 验证用户名密码 + String username = req.getUsername(); + UserDO user = userService.getByUsername(username); + boolean isError = ObjectUtil.isNull(user) || !passwordEncoder.matches(rawPassword, user.getPassword()); + // 检查账号锁定状态 + this.checkUserLocked(req.getUsername(), request, isError); + ValidationUtils.throwIf(isError, "用户名或密码错误"); + // 检查用户状态 + super.checkUserStatus(user); + // 执行认证 + String token = this.authenticate(user, client); + return LoginResp.builder().token(token).build(); + } + + @Override + public void preLogin(AccountAuthReq req, ClientResp client, HttpServletRequest request) { + super.preLogin(req, client, request); + // 校验验证码 + int loginCaptchaEnabled = optionService.getValueByCode2Int("LOGIN_CAPTCHA_ENABLED"); + if (SysConstants.YES.equals(loginCaptchaEnabled)) { + ValidationUtils.throwIfBlank(req.getCaptcha(), "验证码不能为空"); + ValidationUtils.throwIfBlank(req.getUuid(), "验证码标识不能为空"); + String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + req.getUuid(); + String captcha = RedisUtils.get(captchaKey); + ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); + RedisUtils.delete(captchaKey); + ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR); + } + } + @Override public AuthTypeEnum getAuthType() { return AuthTypeEnum.ACCOUNT; } /** - * 校验账号登录请求对象 + * 检测用户是否已被锁定 * - * @param authReq 登录请求参数 + * @param username 用户名 + * @param request 请求对象 + * @param isError 是否登录错误 */ - @Override - public void validate(AccountAuthReq authReq) { - // 获取验证码开关 - int enableCaptcha = optionService.getValueByCode2Int("LOGIN_CAPTCHA_ENABLED"); - - ValidationUtils.validate(authReq); - if (SysConstants.YES.equals(enableCaptcha)) { - ValidationUtils.throwIfEmpty(authReq.getCaptcha(), "验证码不能为空"); - ValidationUtils.throwIfEmpty(authReq.getUuid(), "验证码标识不能为空"); + private void checkUserLocked(String username, HttpServletRequest request, boolean isError) { + // 不锁定 + int maxErrorCount = optionService.getValueByCode2Int(PasswordPolicyEnum.PASSWORD_ERROR_LOCK_COUNT.name()); + if (maxErrorCount <= SysConstants.NO) { + return; } - } - - /** - * 账号登录 - * - * @param authReq 账号登录请求对象 - * @param request HTTP请求对象 - * @return 登录响应 - */ - @Override - public LoginResp login(AccountAuthReq authReq, ClientResp clientResp, HttpServletRequest request) { - this.validate(authReq); - // 解密密码 - String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(authReq.getPassword())); - ValidationUtils.throwIfBlank(rawPassword, "密码解密失败"); - - // 验证用户名密码 - UserDO user = userService.getByUsername(authReq.getUsername()); - boolean isError = user == null || !passwordEncoder.matches(rawPassword, user.getPassword()); - - // 检查账号锁定状态 - loginService.checkUserLocked(authReq.getUsername(), request, isError); - ValidationUtils.throwIf(isError, "用户名或密码错误"); - - // 检查用户状态 - loginService.checkUserStatus(user); - - // 执行登录 - String token = this.authCertificate(user, clientResp); - return LoginResp.builder().token(token).build(); - } - - /** - * 获取认证信息 - * - * @param user 用户信息 - * @param clientResp 客户端信息 - * @return 认证信息 - */ - @Override - public String authCertificate(UserDO user, ClientResp clientResp) { - return super.authCertificate(user, clientResp); + // 检测是否已被锁定 + String key = CacheConstants.USER_PASSWORD_ERROR_KEY_PREFIX + RedisUtils.formatKey(username, JakartaServletUtil + .getClientIP(request)); + int lockMinutes = optionService.getValueByCode2Int(PasswordPolicyEnum.PASSWORD_ERROR_LOCK_MINUTES.name()); + Integer currentErrorCount = ObjectUtil.defaultIfNull(RedisUtils.get(key), 0); + CheckUtils.throwIf(currentErrorCount >= maxErrorCount, "账号锁定 {} 分钟,请稍后再试", lockMinutes); + // 登录成功清除计数 + if (!isError) { + RedisUtils.delete(key); + return; + } + // 登录失败递增计数 + currentErrorCount++; + RedisUtils.set(key, currentErrorCount, Duration.ofMinutes(lockMinutes)); + CheckUtils.throwIf(currentErrorCount >= maxErrorCount, "密码错误已达 {} 次,账号锁定 {} 分钟", maxErrorCount, lockMinutes); } } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/handler/EmailAuthHandler.java b/continew-module-system/src/main/java/top/continew/admin/auth/handler/EmailAuthHandler.java index 0c6e840d..cbc9af64 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/handler/EmailAuthHandler.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/handler/EmailAuthHandler.java @@ -17,17 +17,14 @@ package top.continew.admin.auth.handler; import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import top.continew.admin.auth.AbstractAuthHandler; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.EmailAuthReq; import top.continew.admin.auth.model.resp.LoginResp; -import top.continew.admin.auth.service.LoginService; -import top.continew.admin.auth.AuthHandler; import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.system.model.entity.UserDO; import top.continew.admin.system.model.resp.ClientResp; -import top.continew.admin.system.service.UserService; import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.core.validation.ValidationUtils; @@ -35,73 +32,36 @@ import top.continew.starter.core.validation.ValidationUtils; * 邮箱认证处理器 * * @author KAI + * @author Charles7c * @since 2024/12/22 14:58 */ @Component -@RequiredArgsConstructor -public class EmailAuthHandler extends AbstractAuthHandler implements AuthHandler { +public class EmailAuthHandler extends AbstractAuthHandler { - private final UserService userService; - private final LoginService loginService; + @Override + public LoginResp login(EmailAuthReq req, ClientResp client, HttpServletRequest request) { + // 验证邮箱 + UserDO user = userService.getByEmail(req.getEmail()); + ValidationUtils.throwIfNull(user, "此邮箱未绑定本系统账号"); + // 检查用户状态 + super.checkUserStatus(user); + // 执行认证 + String token = super.authenticate(user, client); + return LoginResp.builder().token(token).build(); + } + + @Override + public void preLogin(EmailAuthReq req, ClientResp client, HttpServletRequest request) { + String email = req.getEmail(); + String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email; + String captcha = RedisUtils.get(captchaKey); + ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); + ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR); + RedisUtils.delete(captchaKey); + } - /** - * 获取认证类型 - * - * @return 邮箱认证类型 - */ @Override public AuthTypeEnum getAuthType() { return AuthTypeEnum.EMAIL; } - - /** - * 校验邮箱登录请求对象 - * - * @param authReq 邮箱登录请求参数 - */ - @Override - public void validate(EmailAuthReq authReq) { - ValidationUtils.validate(authReq); - } - - /** - * 邮箱登录 - * - * @param authReq 邮箱登录请求对象 - * @param request HTTP请求对象 - * @return 登录响应 - */ - @Override - public LoginResp login(EmailAuthReq authReq, ClientResp clientResp, HttpServletRequest request) { - this.validate(authReq); - - String email = authReq.getEmail(); - String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email; - String captcha = RedisUtils.get(captchaKey); - ValidationUtils.throwIfBlank(captcha, AbstractAuthHandler.CAPTCHA_EXPIRED); - ValidationUtils.throwIfNotEqualIgnoreCase(authReq.getCaptcha(), captcha, CAPTCHA_ERROR); - RedisUtils.delete(captchaKey); - // 验证邮箱 - UserDO user = userService.getByEmail(authReq.getEmail()); - ValidationUtils.throwIfNull(user, "此邮箱未绑定本系统账号"); - - // 检查用户状态 - loginService.checkUserStatus(user); - - // 执行登录 - String token = this.authCertificate(user, clientResp); - return LoginResp.builder().token(token).build(); - } - - /** - * 获取登录凭证 - * - * @param user 用户信息 - * @param clientResp 客户端信息 - * @return token 认证信息 - */ - @Override - public String authCertificate(UserDO user, ClientResp clientResp) { - return super.authCertificate(user, clientResp); - } } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/handler/PhoneAuthHandler.java b/continew-module-system/src/main/java/top/continew/admin/auth/handler/PhoneAuthHandler.java index 72189669..6d558262 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/handler/PhoneAuthHandler.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/handler/PhoneAuthHandler.java @@ -17,17 +17,14 @@ package top.continew.admin.auth.handler; import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import top.continew.admin.auth.AbstractAuthHandler; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.PhoneAuthReq; import top.continew.admin.auth.model.resp.LoginResp; -import top.continew.admin.auth.service.LoginService; -import top.continew.admin.auth.AuthHandler; import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.system.model.entity.UserDO; import top.continew.admin.system.model.resp.ClientResp; -import top.continew.admin.system.service.UserService; import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.core.validation.ValidationUtils; @@ -35,75 +32,36 @@ import top.continew.starter.core.validation.ValidationUtils; * 手机号认证处理器 * * @author KAI + * @author Charles7c * @since 2024/12/22 14:59 */ @Component -@RequiredArgsConstructor -public class PhoneAuthHandler extends AbstractAuthHandler implements AuthHandler { +public class PhoneAuthHandler extends AbstractAuthHandler { - private final UserService userService; - private final LoginService loginService; + @Override + public LoginResp login(PhoneAuthReq req, ClientResp client, HttpServletRequest request) { + // 验证手机号 + UserDO user = userService.getByPhone(req.getPhone()); + ValidationUtils.throwIfNull(user, "此手机号未绑定本系统账号"); + // 检查用户状态 + super.checkUserStatus(user); + // 执行认证 + String token = super.authenticate(user, client); + return LoginResp.builder().token(token).build(); + } + + @Override + public void preLogin(PhoneAuthReq req, ClientResp client, HttpServletRequest request) { + String phone = req.getPhone(); + String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone; + String captcha = RedisUtils.get(captchaKey); + ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); + ValidationUtils.throwIfNotEqualIgnoreCase(req.getCaptcha(), captcha, CAPTCHA_ERROR); + RedisUtils.delete(captchaKey); + } - /** - * 获取认证类型 - * - * @return 手机号认证类型 - */ @Override public AuthTypeEnum getAuthType() { return AuthTypeEnum.PHONE; } - - /** - * 校验手机号登录请求对象 - * - * @param authReq 手机号登录请求参数 - */ - @Override - public void validate(PhoneAuthReq authReq) { - ValidationUtils.validate(authReq); - } - - /** - * 手机号登录 - * - * @param authReq 手机号登录请求对象 - * @param request HTTP请求对象 - * @return 登录响应 - */ - @Override - public LoginResp login(PhoneAuthReq authReq, ClientResp clientResp, HttpServletRequest request) { - //校验参数 - this.validate(authReq); - - String phone = authReq.getPhone(); - String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone; - String captcha = RedisUtils.get(captchaKey); - ValidationUtils.throwIfBlank(captcha, AbstractAuthHandler.CAPTCHA_EXPIRED); - ValidationUtils.throwIfNotEqualIgnoreCase(authReq.getCaptcha(), captcha, AbstractAuthHandler.CAPTCHA_ERROR); - RedisUtils.delete(captchaKey); - - // 验证手机号 - UserDO user = userService.getByPhone(authReq.getPhone()); - ValidationUtils.throwIfNull(user, "此手机号未绑定本系统账号"); - - // 检查用户状态 - loginService.checkUserStatus(user); - - // 执行登录 - String token = this.authCertificate(user, clientResp); - return LoginResp.builder().token(token).build(); - } - - /** - * 获取登录凭证 - * - * @param user 用户信息 - * @param clientResp 客户端信息 - * @return token 认证信息 - */ - @Override - public String authCertificate(UserDO user, ClientResp clientResp) { - return super.authCertificate(user, clientResp); - } } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/handler/SocialAuthHandler.java b/continew-module-system/src/main/java/top/continew/admin/auth/handler/SocialAuthHandler.java index 1bd9a17f..010bc76d 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/handler/SocialAuthHandler.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/handler/SocialAuthHandler.java @@ -18,6 +18,7 @@ package top.continew.admin.auth.handler; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.ReUtil; @@ -30,84 +31,59 @@ import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.request.AuthRequest; import org.springframework.stereotype.Component; -import top.continew.admin.auth.AuthHandler; +import top.continew.admin.auth.AbstractAuthHandler; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.SocialAuthReq; import top.continew.admin.auth.model.resp.LoginResp; -import top.continew.admin.auth.service.LoginService; import top.continew.admin.common.constant.RegexConstants; import top.continew.admin.common.constant.SysConstants; import top.continew.admin.common.enums.GenderEnum; +import top.continew.admin.system.enums.MessageTemplateEnum; +import top.continew.admin.system.enums.MessageTypeEnum; import top.continew.admin.system.model.entity.RoleDO; import top.continew.admin.system.model.entity.UserDO; import top.continew.admin.system.model.entity.UserSocialDO; +import top.continew.admin.system.model.req.MessageReq; import top.continew.admin.system.model.resp.ClientResp; -import top.continew.admin.system.service.RoleService; +import top.continew.admin.system.service.MessageService; import top.continew.admin.system.service.UserRoleService; -import top.continew.admin.system.service.UserService; import top.continew.admin.system.service.UserSocialService; +import top.continew.starter.core.autoconfigure.project.ProjectProperties; import top.continew.starter.core.exception.BadRequestException; import top.continew.starter.core.validation.ValidationUtils; +import top.continew.starter.messaging.websocket.util.WebSocketUtils; import java.time.LocalDateTime; import java.util.Collections; +import java.util.List; /** - * 手机号认证处理器 + * 第三方账号认证处理器 * * @author KAI * @since 2024/12/25 14:21 */ @Component @RequiredArgsConstructor -public class SocialAuthHandler extends AbstractAuthHandler implements AuthHandler { +public class SocialAuthHandler extends AbstractAuthHandler { + private final AuthRequestFactory authRequestFactory; private final UserSocialService userSocialService; - private final UserService userService; - private final RoleService roleService; private final UserRoleService userRoleService; - private final LoginService loginService; + private final MessageService messageService; + private final ProjectProperties projectProperties; - /** - * 获取认证类型 - * - * @return 第三方认证类型 - */ @Override - public AuthTypeEnum getAuthType() { - return AuthTypeEnum.SOCIAL_AUTH; - } - - /** - * 校验第三方登录请求对象 - * - * @param authReq 登录请求参数 - */ - @Override - public void validate(SocialAuthReq authReq) { - ValidationUtils.validate(authReq); - } - - /** - * 第三方登录 - * - * @param authReq 第三方登录请求对象 - * @param request HTTP请求对象 - * @return 登录响应 - */ - @Override - public LoginResp login(SocialAuthReq authReq, ClientResp clientResp, HttpServletRequest request) { - this.validate(authReq); - if (StpUtil.isLogin()) { - StpUtil.logout(); - } - AuthRequest authRequest = this.getAuthRequest(authReq.getSource()); + public LoginResp login(SocialAuthReq req, ClientResp client, HttpServletRequest request) { + // 获取第三方登录信息 + AuthRequest authRequest = this.getAuthRequest(req.getSource()); AuthCallback callback = new AuthCallback(); - callback.setCode(authReq.getCode()); - callback.setState(authReq.getState()); + callback.setCode(req.getCode()); + callback.setState(req.getState()); AuthResponse response = authRequest.login(callback); ValidationUtils.throwIf(!response.ok(), response.getMsg()); AuthUser authUser = response.getData(); + // 如未绑定则自动注册新用户,保存或更新关联信息 String source = authUser.getSource(); String openId = authUser.getUuid(); UserSocialDO userSocial = userSocialService.getBySourceAndOpenId(source, openId); @@ -136,19 +112,39 @@ public class SocialAuthHandler extends AbstractAuthHandler implements AuthHandle userSocial.setUserId(userId); userSocial.setSource(source); userSocial.setOpenId(openId); - loginService.sendSecurityMsg(user); + this.sendSecurityMsg(user); } else { user = BeanUtil.copyProperties(userService.getById(userSocial.getUserId()), UserDO.class); } - loginService.checkUserStatus(user); + // 检查用户状态 + super.checkUserStatus(user); userSocial.setMetaJson(JSONUtil.toJsonStr(authUser)); userSocial.setLastLoginTime(LocalDateTime.now()); userSocialService.saveOrUpdate(userSocial); - // 执行登录 - String token = this.authCertificate(user, clientResp); + // 执行认证 + String token = super.authenticate(user, client); return LoginResp.builder().token(token).build(); } + @Override + public void preLogin(SocialAuthReq req, ClientResp client, HttpServletRequest request) { + super.preLogin(req, client, request); + if (StpUtil.isLogin()) { + StpUtil.logout(); + } + } + + @Override + public AuthTypeEnum getAuthType() { + return AuthTypeEnum.SOCIAL; + } + + /** + * 获取 AuthRequest + * + * @param source 平台名称 + * @return AuthRequest + */ private AuthRequest getAuthRequest(String source) { try { return authRequestFactory.get(source); @@ -158,15 +154,20 @@ public class SocialAuthHandler extends AbstractAuthHandler implements AuthHandle } /** - * 获取认证信息 + * 发送安全消息 * - * @param user 用户信息 - * @param clientResp 客户端信息 - * @return 认证信息 + * @param user 用户信息 */ - @Override - protected String authCertificate(UserDO user, ClientResp clientResp) { - return super.authCertificate(user, clientResp); + private void sendSecurityMsg(UserDO user) { + MessageReq req = new MessageReq(); + MessageTemplateEnum socialRegister = MessageTemplateEnum.SOCIAL_REGISTER; + req.setTitle(socialRegister.getTitle().formatted(projectProperties.getName())); + req.setContent(socialRegister.getContent().formatted(user.getNickname())); + req.setType(MessageTypeEnum.SECURITY); + messageService.add(req, CollUtil.toList(user.getId())); + List tokenList = StpUtil.getTokenValueListByLoginId(user.getId()); + for (String token : tokenList) { + WebSocketUtils.sendMessage(token, "1"); + } } - } diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AccountAuthReq.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AccountAuthReq.java index d56d1414..082f37c6 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AccountAuthReq.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AccountAuthReq.java @@ -21,17 +21,16 @@ import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serial; -import java.io.Serializable; /** - * 账号登录参数 + * 账号认证参数 * * @author Charles7c * @since 2022/12/21 20:43 */ @Data -@Schema(description = "账号登录参数") -public class AccountAuthReq extends AuthReq implements Serializable { +@Schema(description = "账号认证参数") +public class AccountAuthReq extends AuthReq { @Serial private static final long serialVersionUID = 1L; diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AuthReq.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AuthReq.java index 7820faca..4ceaa00e 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AuthReq.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/AuthReq.java @@ -20,27 +20,42 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.Data; +import top.continew.admin.auth.enums.AuthTypeEnum; + +import java.io.Serial; +import java.io.Serializable; /** - * 登录参数基础类 + * 认证参数基类 * * @author KAI + * @author Charles7c * @since 2024/12/22 15:16 */ @Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "authType", visible = true) -@JsonSubTypes({@JsonSubTypes.Type(value = AccountAuthReq.class, name = "account"), - @JsonSubTypes.Type(value = EmailAuthReq.class, name = "email"), - @JsonSubTypes.Type(value = PhoneAuthReq.class, name = "phone"), - @JsonSubTypes.Type(value = SocialAuthReq.class, name = "socialAuth")}) -public abstract class AuthReq { +@JsonSubTypes({@JsonSubTypes.Type(value = AccountAuthReq.class, name = "ACCOUNT"), + @JsonSubTypes.Type(value = EmailAuthReq.class, name = "EMAIL"), + @JsonSubTypes.Type(value = PhoneAuthReq.class, name = "PHONE"), + @JsonSubTypes.Type(value = SocialAuthReq.class, name = "SOCIAL")}) +public class AuthReq implements Serializable { - @Schema(description = "客户端id") - @NotBlank(message = "客户端id不能为空") + @Serial + private static final long serialVersionUID = 1L; + + /** + * 客户端 ID + */ + @Schema(description = "客户端 ID") + @NotBlank(message = "客户端ID不能为空") private String clientId; + /** + * 认证类型 + */ @Schema(description = "认证类型") - @NotBlank(message = "认证类型不能为空") - private String authType; + @NotNull(message = "认证类型非法") + private AuthTypeEnum authType; } diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/EmailAuthReq.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/EmailAuthReq.java index f84d0e3d..551685ae 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/EmailAuthReq.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/EmailAuthReq.java @@ -24,17 +24,16 @@ import lombok.Data; import org.hibernate.validator.constraints.Length; import java.io.Serial; -import java.io.Serializable; /** - * 邮箱登录参数 + * 邮箱认证参数 * * @author Charles7c * @since 2023/10/23 20:15 */ @Data -@Schema(description = "邮箱登录参数") -public class EmailAuthReq extends AuthReq implements Serializable { +@Schema(description = "邮箱认证参数") +public class EmailAuthReq extends AuthReq { @Serial private static final long serialVersionUID = 1L; diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/PhoneAuthReq.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/PhoneAuthReq.java index 5072b624..9b2c0c39 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/PhoneAuthReq.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/PhoneAuthReq.java @@ -24,17 +24,16 @@ import lombok.Data; import org.hibernate.validator.constraints.Length; import java.io.Serial; -import java.io.Serializable; /** - * 手机号登录参数 + * 手机号认证参数 * * @author Charles7c * @since 2023/10/26 22:37 */ @Data -@Schema(description = "手机号登录参数") -public class PhoneAuthReq extends AuthReq implements Serializable { +@Schema(description = "手机号认证参数") +public class PhoneAuthReq extends AuthReq { @Serial private static final long serialVersionUID = 1L; diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/SocialAuthReq.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/SocialAuthReq.java index 2eb749f6..e3676b1f 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/req/SocialAuthReq.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/req/SocialAuthReq.java @@ -20,30 +20,40 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Data; +import java.io.Serial; + /** - * 第三方登录参数 + * 第三方账号认证参数 * * @author KAI + * @author Charles7c * @since 2024/12/25 15:43 */ @Data -@Schema(description = "第三方登录参数") +@Schema(description = "第三方账号认证参数") public class SocialAuthReq extends AuthReq { + + @Serial + private static final long serialVersionUID = 1L; + /** * 第三方登录平台 */ + @Schema(description = "第三方登录平台", example = "gitee") @NotBlank(message = "第三方登录平台不能为空") private String source; /** - * 第三方登录code + * 授权码 */ - @NotBlank(message = "第三方登录code不能为空") + @Schema(description = "授权码", example = "a08d33e9e577fb339de027499784ed4e871d6f62ae65b459153e906ab546bd56") + @NotBlank(message = "授权码不能为空") private String code; /** - * 第三方登录state + * 状态码 */ - @NotBlank(message = "第三方登录state不能为空") + @Schema(description = "状态码", example = "2ca8d8baf437eb374efaa1191a3d") + @NotBlank(message = "状态码不能为空") private String state; } diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java index e890258e..c0c166aa 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java @@ -24,14 +24,14 @@ import java.io.Serial; import java.io.Serializable; /** - * 令牌信息 + * 登录响应参数 * * @author Charles7c * @since 2022/12/21 20:42 */ @Data @Builder -@Schema(description = "令牌信息") +@Schema(description = "登录响应参数") public class LoginResp implements Serializable { @Serial diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/service/LoginService.java b/continew-module-system/src/main/java/top/continew/admin/auth/service/AuthService.java similarity index 53% rename from continew-module-system/src/main/java/top/continew/admin/auth/service/LoginService.java rename to continew-module-system/src/main/java/top/continew/admin/auth/service/AuthService.java index 529ec973..8447a5e6 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/service/LoginService.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/service/AuthService.java @@ -17,51 +17,28 @@ package top.continew.admin.auth.service; import jakarta.servlet.http.HttpServletRequest; -import me.zhyd.oauth.model.AuthUser; +import top.continew.admin.auth.model.req.AuthReq; +import top.continew.admin.auth.model.resp.LoginResp; import top.continew.admin.auth.model.resp.RouteResp; -import top.continew.admin.system.model.entity.UserDO; import java.util.List; /** - * 登录业务接口 + * 认证业务接口 * * @author Charles7c * @since 2022/12/21 21:48 */ -public interface LoginService { +public interface AuthService { /** - * 检查用户状态 + * 登录 * - * @param user 用户信息 + * @param req 登录请求参数 + * @param request 请求对象 + * @return 登录响应参数 */ - void checkUserStatus(UserDO user); - - /** - * 检查用户是否被锁定 - * - * @param username 用户名 - * @param request 请求对象 - * @param isError 是否登录错误 - */ - void checkUserLocked(String username, HttpServletRequest request, boolean isError); - - /** - * 执行登录操作 - * - * @param user 用户信息 - * @return token - */ - String login(UserDO user); - - /** - * 三方账号登录 - * - * @param authUser 三方账号信息 - * @return 令牌 - */ - String socialLogin(AuthUser authUser); + LoginResp login(AuthReq req, HttpServletRequest request); /** * 构建路由树 @@ -70,11 +47,4 @@ public interface LoginService { * @return 路由树 */ List buildRouteTree(Long userId); - - /** - * 发送安全消息 - * - * @param user 用户信息 - */ - void sendSecurityMsg(UserDO user); } diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java new file mode 100644 index 00000000..13eddb47 --- /dev/null +++ b/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.auth.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import top.continew.admin.auth.AuthHandler; +import top.continew.admin.auth.AuthStrategy; +import top.continew.admin.auth.enums.AuthTypeEnum; +import top.continew.admin.auth.model.req.AuthReq; +import top.continew.admin.auth.model.resp.LoginResp; +import top.continew.admin.auth.model.resp.RouteResp; +import top.continew.admin.auth.service.AuthService; +import top.continew.admin.common.constant.SysConstants; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.system.enums.MenuTypeEnum; +import top.continew.admin.system.model.resp.ClientResp; +import top.continew.admin.system.model.resp.MenuResp; +import top.continew.admin.system.service.ClientService; +import top.continew.admin.system.service.MenuService; +import top.continew.admin.system.service.RoleService; +import top.continew.starter.core.validation.ValidationUtils; +import top.continew.starter.extension.crud.annotation.TreeField; +import top.continew.starter.extension.crud.autoconfigure.CrudProperties; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * 认证业务实现 + * + * @author Charles7c + * @since 2022/12/21 21:49 + */ +@Service +@RequiredArgsConstructor +public class AuthServiceImpl implements AuthService { + + private final AuthStrategy authStrategy; + private final ClientService clientService; + private final RoleService roleService; + private final MenuService menuService; + private final CrudProperties crudProperties; + + @Override + public LoginResp login(AuthReq req, HttpServletRequest request) { + AuthTypeEnum authType = req.getAuthType(); + // 校验客户端 + ClientResp client = clientService.getByClientId(req.getClientId()); + ValidationUtils.throwIfNull(client, "客户端不存在"); + ValidationUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(client.getStatus()), "客户端已禁用"); + ValidationUtils.throwIf(!client.getAuthType().contains(authType.getValue()), "该客户端暂未授权 [{}] 认证", authType + .getDescription()); + // 获取处理器 + AuthHandler authHandler = authStrategy.getHandler(authType); + // 登录前置处理 + authHandler.preLogin(req, client, request); + // 登录 + LoginResp loginResp = authHandler.login(req, client, request); + // 登录后置处理 + authHandler.postLogin(req, client, request); + return loginResp; + } + + @Override + public List buildRouteTree(Long userId) { + Set roleCodeSet = roleService.listCodeByUserId(userId); + if (CollUtil.isEmpty(roleCodeSet)) { + return new ArrayList<>(0); + } + // 查询菜单列表 + Set menuSet = new LinkedHashSet<>(); + if (roleCodeSet.contains(SysConstants.SUPER_ROLE_CODE)) { + menuSet.addAll(menuService.listAll()); + } else { + roleCodeSet.forEach(roleCode -> menuSet.addAll(menuService.listByRoleCode(roleCode))); + } + List menuList = menuSet.stream().filter(m -> !MenuTypeEnum.BUTTON.equals(m.getType())).toList(); + if (CollUtil.isEmpty(menuList)) { + return new ArrayList<>(0); + } + // 构建路由树 + TreeField treeField = MenuResp.class.getDeclaredAnnotation(TreeField.class); + TreeNodeConfig treeNodeConfig = crudProperties.getTree().genTreeNodeConfig(treeField); + List> treeList = TreeUtil.build(menuList, treeField.rootId(), treeNodeConfig, (m, tree) -> { + tree.setId(m.getId()); + tree.setParentId(m.getParentId()); + tree.setName(m.getTitle()); + tree.setWeight(m.getSort()); + tree.putExtra("type", m.getType().getValue()); + tree.putExtra("path", m.getPath()); + tree.putExtra("name", m.getName()); + tree.putExtra("component", m.getComponent()); + tree.putExtra("redirect", m.getRedirect()); + tree.putExtra("icon", m.getIcon()); + tree.putExtra("isExternal", m.getIsExternal()); + tree.putExtra("isCache", m.getIsCache()); + tree.putExtra("isHidden", m.getIsHidden()); + tree.putExtra("permission", m.getPermission()); + }); + return BeanUtil.copyToList(treeList, RouteResp.class); + } +} diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java deleted file mode 100644 index e021bd2d..00000000 --- a/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.auth.service.impl; - -import cn.dev33.satoken.stp.SaLoginConfig; -import cn.dev33.satoken.stp.StpUtil; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.tree.Tree; -import cn.hutool.core.lang.tree.TreeNodeConfig; -import cn.hutool.core.lang.tree.TreeUtil; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.RandomUtil; -import cn.hutool.core.util.ReUtil; -import cn.hutool.extra.servlet.JakartaServletUtil; -import cn.hutool.json.JSONUtil; -import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; -import me.zhyd.oauth.model.AuthUser; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import top.continew.admin.auth.model.resp.RouteResp; -import top.continew.admin.auth.service.LoginService; -import top.continew.admin.common.constant.CacheConstants; -import top.continew.admin.common.constant.RegexConstants; -import top.continew.admin.common.constant.SysConstants; -import top.continew.admin.common.context.RoleContext; -import top.continew.admin.common.context.UserContext; -import top.continew.admin.common.context.UserContextHolder; -import top.continew.admin.common.context.UserExtraContext; -import top.continew.admin.common.enums.DisEnableStatusEnum; -import top.continew.admin.common.enums.GenderEnum; -import top.continew.admin.system.enums.MenuTypeEnum; -import top.continew.admin.system.enums.MessageTemplateEnum; -import top.continew.admin.system.enums.MessageTypeEnum; -import top.continew.admin.system.enums.PasswordPolicyEnum; -import top.continew.admin.system.model.entity.DeptDO; -import top.continew.admin.system.model.entity.RoleDO; -import top.continew.admin.system.model.entity.UserDO; -import top.continew.admin.system.model.entity.UserSocialDO; -import top.continew.admin.system.model.req.MessageReq; -import top.continew.admin.system.model.resp.MenuResp; -import top.continew.admin.system.service.*; -import top.continew.starter.cache.redisson.util.RedisUtils; -import top.continew.starter.core.autoconfigure.project.ProjectProperties; -import top.continew.starter.core.validation.CheckUtils; -import top.continew.starter.extension.crud.annotation.TreeField; -import top.continew.starter.extension.crud.autoconfigure.CrudProperties; -import top.continew.starter.messaging.websocket.util.WebSocketUtils; -import top.continew.starter.web.util.SpringWebUtils; - -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.*; -import java.util.concurrent.CompletableFuture; - -import static top.continew.admin.system.enums.PasswordPolicyEnum.PASSWORD_EXPIRATION_DAYS; - -/** - * 登录业务实现 - * - * @author Charles7c - * @since 2022/12/21 21:49 - */ -@Service -@RequiredArgsConstructor -public class LoginServiceImpl implements LoginService { - - private final ProjectProperties projectProperties; - private final CrudProperties crudProperties; - private final PasswordEncoder passwordEncoder; - private final ThreadPoolTaskExecutor threadPoolTaskExecutor; - private final UserService userService; - private final DeptService deptService; - private final RoleService roleService; - private final MenuService menuService; - private final UserRoleService userRoleService; - private final UserSocialService userSocialService; - private final OptionService optionService; - private final MessageService messageService; - - @Override - @Transactional(rollbackFor = Exception.class) - public String socialLogin(AuthUser authUser) { - String source = authUser.getSource(); - String openId = authUser.getUuid(); - UserSocialDO userSocial = userSocialService.getBySourceAndOpenId(source, openId); - UserDO user; - if (null == userSocial) { - String username = authUser.getUsername(); - String nickname = authUser.getNickname(); - UserDO existsUser = userService.getByUsername(username); - String randomStr = RandomUtil.randomString(RandomUtil.BASE_CHAR, 5); - if (null != existsUser || !ReUtil.isMatch(RegexConstants.USERNAME, username)) { - username = randomStr + IdUtil.fastSimpleUUID(); - } - if (!ReUtil.isMatch(RegexConstants.GENERAL_NAME, nickname)) { - nickname = source.toLowerCase() + randomStr; - } - user = new UserDO(); - user.setUsername(username); - user.setNickname(nickname); - user.setGender(GenderEnum.valueOf(authUser.getGender().name())); - user.setAvatar(authUser.getAvatar()); - user.setDeptId(SysConstants.SUPER_DEPT_ID); - Long userId = userService.add(user); - RoleDO role = roleService.getByCode(SysConstants.SUPER_ROLE_CODE); - userRoleService.assignRolesToUser(Collections.singletonList(role.getId()), userId); - userSocial = new UserSocialDO(); - userSocial.setUserId(userId); - userSocial.setSource(source); - userSocial.setOpenId(openId); - this.sendSecurityMsg(user); - } else { - user = BeanUtil.copyProperties(userService.getById(userSocial.getUserId()), UserDO.class); - } - this.checkUserStatus(user); - userSocial.setMetaJson(JSONUtil.toJsonStr(authUser)); - userSocial.setLastLoginTime(LocalDateTime.now()); - userSocialService.saveOrUpdate(userSocial); - return this.login(user); - } - - @Override - public List buildRouteTree(Long userId) { - Set roleCodeSet = roleService.listCodeByUserId(userId); - if (CollUtil.isEmpty(roleCodeSet)) { - return new ArrayList<>(0); - } - // 查询菜单列表 - Set menuSet = new LinkedHashSet<>(); - if (roleCodeSet.contains(SysConstants.SUPER_ROLE_CODE)) { - menuSet.addAll(menuService.listAll()); - } else { - roleCodeSet.forEach(roleCode -> menuSet.addAll(menuService.listByRoleCode(roleCode))); - } - List menuList = menuSet.stream().filter(m -> !MenuTypeEnum.BUTTON.equals(m.getType())).toList(); - if (CollUtil.isEmpty(menuList)) { - return new ArrayList<>(0); - } - // 构建路由树 - TreeField treeField = MenuResp.class.getDeclaredAnnotation(TreeField.class); - TreeNodeConfig treeNodeConfig = crudProperties.getTree().genTreeNodeConfig(treeField); - List> treeList = TreeUtil.build(menuList, treeField.rootId(), treeNodeConfig, (m, tree) -> { - tree.setId(m.getId()); - tree.setParentId(m.getParentId()); - tree.setName(m.getTitle()); - tree.setWeight(m.getSort()); - tree.putExtra("type", m.getType().getValue()); - tree.putExtra("path", m.getPath()); - tree.putExtra("name", m.getName()); - tree.putExtra("component", m.getComponent()); - tree.putExtra("redirect", m.getRedirect()); - tree.putExtra("icon", m.getIcon()); - tree.putExtra("isExternal", m.getIsExternal()); - tree.putExtra("isCache", m.getIsCache()); - tree.putExtra("isHidden", m.getIsHidden()); - tree.putExtra("permission", m.getPermission()); - }); - return BeanUtil.copyToList(treeList, RouteResp.class); - } - - /** - * 登录并缓存用户信息 - * - * @param user 用户信息 - * @return 令牌 - */ - @Override - public String login(UserDO user) { - Long userId = user.getId(); - CompletableFuture> permissionFuture = CompletableFuture.supplyAsync(() -> roleService - .listPermissionByUserId(userId), threadPoolTaskExecutor); - CompletableFuture> roleFuture = CompletableFuture.supplyAsync(() -> roleService - .listByUserId(userId), threadPoolTaskExecutor); - CompletableFuture passwordExpirationDaysFuture = CompletableFuture.supplyAsync(() -> optionService - .getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name())); - CompletableFuture.allOf(permissionFuture, roleFuture, passwordExpirationDaysFuture); - UserContext userContext = new UserContext(permissionFuture.join(), roleFuture - .join(), passwordExpirationDaysFuture.join()); - BeanUtil.copyProperties(user, userContext); - // 登录并缓存用户信息 - StpUtil.login(userContext.getId(), SaLoginConfig.setExtraData(BeanUtil - .beanToMap(new UserExtraContext(SpringWebUtils.getRequest())))); - UserContextHolder.setContext(userContext); - return StpUtil.getTokenValue(); - } - - /** - * 检查用户状态 - * - * @param user 用户信息 - */ - @Override - public void checkUserStatus(UserDO user) { - CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, user.getStatus(), "此账号已被禁用,如有疑问,请联系管理员"); - DeptDO dept = deptService.getById(user.getDeptId()); - CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, dept.getStatus(), "此账号所属部门已被禁用,如有疑问,请联系管理员"); - } - - /** - * 检测用户是否已被锁定 - * - * @param username 用户名 - * @param request 请求对象 - * @param isError 是否登录错误 - */ - @Override - public void checkUserLocked(String username, HttpServletRequest request, boolean isError) { - // 不锁定 - int maxErrorCount = optionService.getValueByCode2Int(PasswordPolicyEnum.PASSWORD_ERROR_LOCK_COUNT.name()); - if (maxErrorCount <= SysConstants.NO) { - return; - } - // 检测是否已被锁定 - String key = CacheConstants.USER_PASSWORD_ERROR_KEY_PREFIX + RedisUtils.formatKey(username, JakartaServletUtil - .getClientIP(request)); - int lockMinutes = optionService.getValueByCode2Int(PasswordPolicyEnum.PASSWORD_ERROR_LOCK_MINUTES.name()); - Integer currentErrorCount = ObjectUtil.defaultIfNull(RedisUtils.get(key), 0); - CheckUtils.throwIf(currentErrorCount >= maxErrorCount, "账号锁定 {} 分钟,请稍后再试", lockMinutes); - // 登录成功清除计数 - if (!isError) { - RedisUtils.delete(key); - return; - } - // 登录失败递增计数 - currentErrorCount++; - RedisUtils.set(key, currentErrorCount, Duration.ofMinutes(lockMinutes)); - CheckUtils.throwIf(currentErrorCount >= maxErrorCount, "密码错误已达 {} 次,账号锁定 {} 分钟", maxErrorCount, lockMinutes); - } - - /** - * 发送安全消息 - * - * @param user 用户信息 - */ - @Override - public void sendSecurityMsg(UserDO user) { - MessageReq req = new MessageReq(); - MessageTemplateEnum socialRegister = MessageTemplateEnum.SOCIAL_REGISTER; - req.setTitle(socialRegister.getTitle().formatted(projectProperties.getName())); - req.setContent(socialRegister.getContent().formatted(user.getNickname())); - req.setType(MessageTypeEnum.SECURITY); - messageService.add(req, CollUtil.toList(user.getId())); - List tokenList = StpUtil.getTokenValueListByLoginId(user.getId()); - for (String token : tokenList) { - WebSocketUtils.sendMessage(token, "1"); - } - } -} diff --git a/continew-module-system/src/main/java/top/continew/admin/system/mapper/ClientMapper.java b/continew-module-system/src/main/java/top/continew/admin/system/mapper/ClientMapper.java index 5bc6dee2..ded9fa1d 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/mapper/ClientMapper.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/mapper/ClientMapper.java @@ -20,9 +20,9 @@ import top.continew.starter.data.mp.base.BaseMapper; import top.continew.admin.system.model.entity.ClientDO; /** - * 客户端管理 Mapper + * 客户端 Mapper * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ public interface ClientMapper extends BaseMapper {} \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java b/continew-module-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java index 80ed66a7..a94505cc 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java @@ -27,9 +27,9 @@ import java.io.Serial; import java.util.List; /** - * 客户端管理实体 + * 客户端实体 * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ @Data @@ -40,12 +40,12 @@ public class ClientDO extends BaseDO { private static final long serialVersionUID = 1L; /** - * 客户端ID + * 客户端 ID */ private String clientId; /** - * 客户端Key + * 客户端 Key */ private String clientKey; diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/query/ClientQuery.java b/continew-module-system/src/main/java/top/continew/admin/system/model/query/ClientQuery.java index 96cd2a3a..a09df4a7 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/query/ClientQuery.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/query/ClientQuery.java @@ -27,13 +27,13 @@ import java.io.Serializable; import java.util.List; /** - * 客户端管理查询条件 + * 客户端查询条件 * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ @Data -@Schema(description = "客户端管理查询条件") +@Schema(description = "客户端查询条件") public class ClientQuery implements Serializable { @Serial @@ -43,33 +43,30 @@ public class ClientQuery implements Serializable { * 客户端Key */ @Schema(description = "客户端Key") - @Query(type = QueryType.EQ) private String clientKey; /** * 客户端秘钥 */ @Schema(description = "客户端秘钥") - @Query(type = QueryType.EQ) private String clientSecret; /** - * 登录类型 + * 认证类型 */ - @Schema(description = "登录类型") + @Schema(description = "认证类型") @Query(type = QueryType.IN) private List authType; + /** * 客户端类型 */ @Schema(description = "客户端类型") - @Query(type = QueryType.EQ) private String clientType; /** - * 状态(1:启用;2:禁用) + * 状态 */ - @Schema(description = "状态") - @Query(type = QueryType.EQ) + @Schema(description = "状态", example = "1") private DisEnableStatusEnum status; } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java b/continew-module-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java index 09b5eb0d..9c365ecb 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java @@ -28,13 +28,13 @@ import java.io.Serial; import java.util.List; /** - * 创建或修改客户端管理参数 + * 创建或修改客户端参数 * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ @Data -@Schema(description = "创建或修改客户端管理参数") +@Schema(description = "创建或修改客户端参数") public class ClientReq extends BaseReq { @Serial @@ -63,11 +63,12 @@ public class ClientReq extends BaseReq { private String clientSecret; /** - * 登录类型 + * 认证类型 */ - @Schema(description = "登录类型") - @NotNull(message = "登录类型不能为空") + @Schema(description = "认证类型") + @NotNull(message = "认证类型不能为空") private List authType; + /** * 客户端类型 */ @@ -89,9 +90,8 @@ public class ClientReq extends BaseReq { private Integer timeout; /** - * 状态(1:启用;2:禁用) + * 状态 */ - @Schema(description = "状态(1:启用;2:禁用)") - @NotNull(message = "状态(1:启用;2:禁用)不能为空") + @Schema(description = "状态", example = "1") private DisEnableStatusEnum status; } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java index 8afc05f5..cc2464d3 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java @@ -22,19 +22,20 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.starter.extension.crud.model.resp.BaseDetailResp; +import top.continew.starter.file.excel.converter.ExcelBaseEnumConverter; import java.io.Serial; import java.util.List; /** - * 客户端管理详情信息 + * 客户端详情信息 * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ @Data @ExcelIgnoreUnannotated -@Schema(description = "客户端管理详情信息") +@Schema(description = "客户端详情信息") public class ClientDetailResp extends BaseDetailResp { @Serial @@ -44,55 +45,55 @@ public class ClientDetailResp extends BaseDetailResp { * 客户端ID */ @Schema(description = "客户端ID") - @ExcelProperty(value = "客户端ID") + @ExcelProperty(value = "客户端ID", order = 2) private String clientId; /** * 客户端Key */ @Schema(description = "客户端Key") - @ExcelProperty(value = "客户端Key") + @ExcelProperty(value = "客户端Key", order = 3) private String clientKey; /** * 客户端秘钥 */ @Schema(description = "客户端秘钥") - @ExcelProperty(value = "客户端秘钥") + @ExcelProperty(value = "客户端秘钥", order = 4) private String clientSecret; /** * 登录类型 */ @Schema(description = "登录类型") - @ExcelProperty(value = "登录类型") + @ExcelProperty(value = "登录类型", order = 5) private List authType; /** * 客户端类型 */ @Schema(description = "客户端类型") - @ExcelProperty(value = "客户端类型") + @ExcelProperty(value = "客户端类型", order = 6) private String clientType; /** * Token最低活跃频率(-1为不限制) */ @Schema(description = "Token最低活跃频率(-1为不限制)") - @ExcelProperty(value = "Token最低活跃频率(-1为不限制)") + @ExcelProperty(value = "Token最低活跃频率(-1为不限制)", order = 7) private Integer activeTimeout; /** * Token有效期(默认30天,单位:秒) */ @Schema(description = "Token有效期(默认30天,单位:秒)") - @ExcelProperty(value = "Token有效期(默认30天,单位:秒)") + @ExcelProperty(value = "Token有效期(默认30天,单位:秒)", order = 8) private Integer timeout; /** * 状态 */ - @Schema(description = "状态") - @ExcelProperty(value = "状态") + @Schema(description = "状态", example = "1") + @ExcelProperty(value = "状态", converter = ExcelBaseEnumConverter.class, order = 9) private DisEnableStatusEnum status; } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java index e45f5f92..cd6da40a 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java @@ -25,13 +25,13 @@ import java.io.Serial; import java.util.List; /** - * 客户端管理信息 + * 客户端信息 * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ @Data -@Schema(description = "客户端管理信息") +@Schema(description = "客户端信息") public class ClientResp extends BaseResp { @Serial diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/ClientService.java b/continew-module-system/src/main/java/top/continew/admin/system/service/ClientService.java index 4ea45cd8..7c654125 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/service/ClientService.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/service/ClientService.java @@ -23,13 +23,19 @@ import top.continew.admin.system.model.resp.ClientResp; import top.continew.starter.extension.crud.service.BaseService; /** - * 客户端管理业务接口 + * 客户端业务接口 * - * @author MoChou + * @author KAI + * @author Charles7c * @since 2024/12/03 16:04 */ public interface ClientService extends BaseService { - ClientResp getClientByClientId(String clientId); - + /** + * 根据客户端 ID 查詢 + * + * @param clientId 客戶端 ID + * @return 客户端信息 + */ + ClientResp getByClientId(String clientId); } \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java index b813c0ee..2eccf838 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java @@ -17,10 +17,7 @@ package top.continew.admin.system.service.impl; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.system.mapper.ClientMapper; @@ -37,40 +34,38 @@ import top.continew.starter.extension.crud.service.BaseServiceImpl; import java.util.List; /** - * 客户端管理业务实现 + * 客户端业务实现 * - * @author MoChou + * @author KAI + * @author Charles7c * @since 2024/12/03 16:04 */ @Service -@RequiredArgsConstructor public class ClientServiceImpl extends BaseServiceImpl implements ClientService { + @Override - protected void beforeAdd(ClientReq req) { + public void beforeAdd(ClientReq req) { String clientId = DigestUtil.md5Hex(req.getClientKey() + StringConstants.COLON + req.getClientSecret()); req.setClientId(clientId); } - /** - * 通过ClientId获取客户端实例 - * - * @param clientId 客户端id - * @return 客户端响应对象 - */ @Override - public ClientResp getClientByClientId(String clientId) { - ClientDO clientDO = baseMapper.selectOne(new LambdaQueryWrapper() - .eq(ClientDO::getClientId, clientId)); - return BeanUtil.copyProperties(clientDO, ClientResp.class); + public void beforeDelete(List ids) { + // 查询如果删除客户端记录以后是否还存在账号认证的方式,不存在则不允许删除 + List clientList = baseMapper.lambdaQuery() + .in(ClientDO::getId, ids) + .like(ClientDO::getAuthType, AuthTypeEnum.ACCOUNT.getValue()) + .list(); + ValidationUtils.throwIfEmpty(clientList, "请至少保留 [{}] 认证类型", AuthTypeEnum.ACCOUNT.getDescription()); + super.beforeDelete(ids); } @Override - protected void beforeDelete(List ids) { - // 查询如果删除客户端记录以后是否还存在账号认证的方式,不存在则不允许删除 - List clientDOS = baseMapper.selectList(new LambdaQueryWrapper().notIn(ClientDO::getId, ids) - .like(ClientDO::getAuthType, AuthTypeEnum.ACCOUNT.getValue())); - ValidationUtils.throwIfEmpty(clientDOS, StrUtil.format("请至少保留一条{}认证的方式", AuthTypeEnum.ACCOUNT - .getDescription())); - super.beforeDelete(ids); + public ClientResp getByClientId(String clientId) { + return baseMapper.lambdaQuery() + .eq(ClientDO::getClientId, clientId) + .oneOpt() + .map(client -> BeanUtil.copyProperties(client, ClientResp.class)) + .orElse(null); } } \ No newline at end of file diff --git a/continew-webapi/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java b/continew-webapi/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java index 6022d1f2..a3844cca 100644 --- a/continew-webapi/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java +++ b/continew-webapi/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java @@ -146,13 +146,13 @@ public class LogDaoLocalImpl implements LogDao { // 解析登录接口信息 if (requestUri.startsWith(SysConstants.LOGIN_URI) && LogStatusEnum.SUCCESS.equals(logDO.getStatus())) { String requestBody = logRequest.getBody(); - //账号登录设置操作人 + // 解析账号登录用户为操作人 if (requestBody.contains(AuthTypeEnum.ACCOUNT.getValue())) { - AccountAuthReq loginReq = JSONUtil.toBean(requestBody, AccountAuthReq.class); - logDO.setCreateUser(ExceptionUtils.exToNull(() -> userService.getByUsername(loginReq.getUsername()) + AccountAuthReq authReq = JSONUtil.toBean(requestBody, AccountAuthReq.class); + logDO.setCreateUser(ExceptionUtils.exToNull(() -> userService.getByUsername(authReq.getUsername()) .getId())); + return; } - return; } // 解析 Token 信息 Map requestHeaders = logRequest.getHeaders(); diff --git a/continew-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java b/continew-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java index 93165427..e027e76c 100644 --- a/continew-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java +++ b/continew-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java @@ -19,30 +19,23 @@ package top.continew.admin.controller.auth; import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import top.continew.admin.auth.config.AuthHandlerContext; import top.continew.admin.auth.model.req.AuthReq; import top.continew.admin.auth.model.resp.LoginResp; import top.continew.admin.auth.model.resp.RouteResp; import top.continew.admin.auth.model.resp.UserInfoResp; -import top.continew.admin.auth.service.LoginService; +import top.continew.admin.auth.service.AuthService; import top.continew.admin.common.context.UserContext; import top.continew.admin.common.context.UserContextHolder; -import top.continew.admin.system.model.resp.ClientResp; import top.continew.admin.system.model.resp.user.UserDetailResp; -import top.continew.admin.system.service.ClientService; import top.continew.admin.system.service.UserService; -import top.continew.starter.core.exception.BusinessException; -import top.continew.starter.core.validation.ValidationUtils; import top.continew.starter.log.annotation.Log; import java.util.List; @@ -53,44 +46,25 @@ import java.util.List; * @author Charles7c * @since 2022/12/21 20:37 */ -@Slf4j -@Log(module = "登录") @Tag(name = "认证 API") +@Log(module = "登录") +@Validated @RestController @RequiredArgsConstructor @RequestMapping("/auth") public class AuthController { - private final ClientService clientService; + private final AuthService authService; private final UserService userService; - private final LoginService loginService; - - private final AuthHandlerContext authHandlerContext; - @SaIgnore - @Operation(summary = "登录", description = "统一登录入口") + @Operation(summary = "登录", description = "用户登录") @PostMapping("/login") - public LoginResp login(@Validated @RequestBody AuthReq loginReq, HttpServletRequest request) { - // 认证类型 - String authType = loginReq.getAuthType(); - - // 获取并验证客户端信息 - ClientResp clientResp = clientService.getClientByClientId(loginReq.getClientId()); - ValidationUtils.throwIfNull(clientResp, "客户端信息不存在,请检查客户端id是否正确!"); - - // 验证认证类型 - ValidationUtils.throwIf(!clientResp.getAuthType().contains(authType), StrUtil.format("暂未授权此类型:{}", authType)); - try { - // 执行登录策略 - return (LoginResp)authHandlerContext.getHandler(authType).login(loginReq, clientResp, request); - } catch (Exception e) { - log.error("登录失败: {}", e.getMessage(), e); - throw new BusinessException("登录失败: " + e.getMessage()); - } + public LoginResp login(@Validated @RequestBody AuthReq req, HttpServletRequest request) { + return authService.login(req, request); } - @Operation(summary = "用户退出", description = "注销用户的当前登录") + @Operation(summary = "登出", description = "注销用户的当前登录") @Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER) @PostMapping("/logout") public Object logout() { @@ -114,8 +88,8 @@ public class AuthController { @Log(ignore = true) @Operation(summary = "获取路由信息", description = "获取登录用户的路由信息") - @GetMapping("/route") + @GetMapping("/user/route") public List listRoute() { - return loginService.buildRouteTree(UserContextHolder.getUserId()); + return authService.buildRouteTree(UserContextHolder.getUserId()); } } diff --git a/continew-webapi/src/main/java/top/continew/admin/controller/auth/SocialAuthController.java b/continew-webapi/src/main/java/top/continew/admin/controller/auth/SocialAuthController.java index 26ce8ef3..5c2bfbe7 100644 --- a/continew-webapi/src/main/java/top/continew/admin/controller/auth/SocialAuthController.java +++ b/continew-webapi/src/main/java/top/continew/admin/controller/auth/SocialAuthController.java @@ -17,24 +17,20 @@ package top.continew.admin.controller.auth; import cn.dev33.satoken.annotation.SaIgnore; -import cn.dev33.satoken.stp.StpUtil; import com.xkcoding.justauth.AuthRequestFactory; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import me.zhyd.oauth.model.AuthCallback; -import me.zhyd.oauth.model.AuthResponse; -import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; -import org.springframework.web.bind.annotation.*; -import top.continew.admin.auth.model.resp.LoginResp; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import top.continew.admin.auth.model.resp.SocialAuthAuthorizeResp; -import top.continew.admin.auth.service.LoginService; import top.continew.starter.core.exception.BadRequestException; -import top.continew.starter.core.validation.ValidationUtils; import top.continew.starter.log.annotation.Log; /** @@ -51,7 +47,6 @@ import top.continew.starter.log.annotation.Log; @RequestMapping("/oauth") public class SocialAuthController { - private final LoginService loginService; private final AuthRequestFactory authRequestFactory; @Operation(summary = "三方账号登录授权", description = "三方账号登录授权") @@ -64,21 +59,6 @@ public class SocialAuthController { .build(); } - @Operation(summary = "三方账号登录", description = "三方账号登录") - @Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH) - @PostMapping("/{source}") - public LoginResp login(@PathVariable String source, @RequestBody AuthCallback callback) { - if (StpUtil.isLogin()) { - StpUtil.logout(); - } - AuthRequest authRequest = this.getAuthRequest(source); - AuthResponse response = authRequest.login(callback); - ValidationUtils.throwIf(!response.ok(), response.getMsg()); - AuthUser authUser = response.getData(); - String token = loginService.socialLogin(authUser); - return LoginResp.builder().token(token).build(); - } - private AuthRequest getAuthRequest(String source) { try { return authRequestFactory.get(source); diff --git a/continew-webapi/src/main/java/top/continew/admin/controller/system/ClientController.java b/continew-webapi/src/main/java/top/continew/admin/controller/system/ClientController.java index de468297..c9f9fcda 100644 --- a/continew-webapi/src/main/java/top/continew/admin/controller/system/ClientController.java +++ b/continew-webapi/src/main/java/top/continew/admin/controller/system/ClientController.java @@ -28,12 +28,12 @@ import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.continew.starter.extension.crud.enums.Api; /** - * 客户端管理管理 API + * 客户端管理 API * - * @author MoChou + * @author KAI * @since 2024/12/03 16:04 */ -@Tag(name = "客户端管理管理 API") +@Tag(name = "客户端管理 API") @RestController @CrudRequestMapping(value = "/system/client", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT}) public class ClientController extends BaseController { diff --git a/continew-webapi/src/main/resources/db/changelog/mysql/main_data.sql b/continew-webapi/src/main/resources/db/changelog/mysql/main_data.sql index 6f767215..bd6c7d25 100644 --- a/continew-webapi/src/main/resources/db/changelog/mysql/main_data.sql +++ b/continew-webapi/src/main/resources/db/changelog/mysql/main_data.sql @@ -1,6 +1,6 @@ -- liquibase formatted sql --- changeset Charles7c:1 +-- changeset charles7c:1 -- comment 初始化表数据 -- 初始化默认菜单 INSERT INTO `sys_menu` @@ -76,6 +76,13 @@ VALUES (1114, '修改', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:update', 4, 1, 1, NOW()), (1115, '删除', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:delete', 5, 1, 1, NOW()), +( 1180, '客户端管理', 1000, 2, '/system/client', 'SystemClient', 'system/client/index', NULL, 'mobile', b'0', b'0', b'0', NULL, 9, 1, 1, NOW()), +(1181, '列表', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:list', 1, 1, 1, NOW()), +(1182, '详情', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:detail', 2, 1, 1, NOW()), +(1183, '新增', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:add', 3, 1, 1, NOW()), +(1184, '修改', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:update', 4, 1, 1, NOW()), +(1185, '删除', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:delete', 5, 1, 1, NOW()), + (1190, '系统配置', 1000, 2, '/system/config', 'SystemConfig', 'system/config/index', NULL, 'config', b'0', b'0', b'0', NULL, 999, 1, 1, NOW()), (1191, '查看', 1190, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:config:list', 1, 1, 1, NOW()), (1192, '修改', 1190, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:config:update', 2, 1, 1, NOW()), @@ -150,7 +157,8 @@ INSERT INTO `sys_dict` (`id`, `name`, `code`, `description`, `is_system`, `create_user`, `create_time`) VALUES (1, '公告类型', 'notice_type', NULL, b'1', 1, NOW()), -(2, '消息类型', 'message_type', NULL, b'1', 1, NOW()); +(2, '消息类型', 'message_type', NULL, b'1', 1, NOW()), +(3, '客户端类型', 'client_type', NULL, b'1', 1, NOW()); INSERT INTO `sys_dict_item` (`id`, `label`, `value`, `color`, `sort`, `description`, `status`, `dict_id`, `create_user`, `create_time`) @@ -158,7 +166,10 @@ VALUES (1, '通知', '1', 'blue', 1, NULL, 1, 1, 1, NOW()), (2, '活动', '2', 'orangered', 2, NULL, 1, 1, 1, NOW()), (3, '安全消息', '1', 'blue', 1, NULL, 1, 2, 1, NOW()), -(4, '活动消息', '2', 'orangered', 2, NULL, 1, 2, 1, NOW()); +(4, '活动消息', '2', 'orangered', 2, NULL, 1, 2, 1, NOW()), +(5, '桌面端', 'PC', 'blue', 1, NULL, 1, 3, 1, NOW()), +(6, '安卓', 'ANDROID', '#148628', 2, NULL, 1, 3, 1, NOW()), +(7, '小程序', 'XCX', '#7930AD', 3, NULL, 1, 3, 1, NOW()); -- 初始化默认用户和角色关联数据 INSERT INTO `sys_user_role` @@ -188,30 +199,8 @@ VALUES (1, '开发环境', 'local_dev', 2, NULL, NULL, NULL, 'C:/continew-admin/data/file/', 'http://localhost:8000/file', '本地存储', b'1', 1, 1, 1, NOW()), (2, '生产环境', 'local_prod', 2, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', b'0', 2, 2, 1, NOW()); --- 客户端管理管理菜单 -INSERT INTO `sys_menu` -(`title`, `parent_id`, `type`, `path`, `name`, `component`, `redirect`, `icon`, `is_external`, `is_cache`, `is_hidden`, `permission`, `sort`, `status`, `create_user`, `create_time`, `update_user`, `update_time`) +-- 初始化客户端数据 +INSERT INTO `sys_client` +(`id`, `client_id`, `client_key`, `client_secret`, `auth_type`, `client_type`, `active_timeout`, `timeout`, `status`, `create_user`, `create_time`) VALUES -( '客户端管理', 1000, 2, '/system/client', 'SystemClient', 'system/client/index', NULL, 'mobile', b'0', b'0', b'0', NULL, 9, 1, 1, NOW(), NULL, NULL); - -SET @parentId = LAST_INSERT_ID(); - --- 客户端管理管理按钮 -INSERT INTO `sys_menu` -(`title`, `parent_id`, `type`, `path`, `name`, `component`, `redirect`, `icon`, `is_external`, `is_cache`, `is_hidden`, `permission`, `sort`, `status`, `create_user`, `create_time`, `update_user`, `update_time`) -VALUES - ('列表', @parentId, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:list', 1, 1, 1, NOW(), NULL, NULL), - ('详情', @parentId, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:detail', 2, 1, 1, NOW(), NULL, NULL), - ('新增', @parentId, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:add', 3, 1, 1, NOW(), NULL, NULL), - ('修改', @parentId, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:update', 4, 1, 1, NOW(), NULL, NULL), - ('删除', @parentId, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:delete', 5, 1, 1, NOW(), NULL, NULL), - ('导出', @parentId, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:export', 6, 1, 1, NOW(), NULL, NULL); --- 插入客户端字典数据 -INSERT INTO `sys_dict` (`id`, `name`, `code`, `description`, `is_system`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (4, '客户端类型', 'client_type', NULL, b'0', 1, '2024-12-17 18:09:37', NULL, NULL); -INSERT INTO `sys_dict_item` (`id`, `label`, `value`, `color`, `sort`, `description`, `status`, `dict_id`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (659457796923719711, '桌面端', 'pc', 'blue', 999, NULL, 1, 4, 1, '2024-12-17 18:09:51', NULL, NULL); -INSERT INTO `sys_dict_item` (`id`, `label`, `value`, `color`, `sort`, `description`, `status`, `dict_id`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (659457877756346402, '安卓', 'android', '#148628', 999, NULL, 1, 4, 1, '2024-12-17 18:10:10', NULL, NULL); -INSERT INTO `sys_dict_item` (`id`, `label`, `value`, `color`, `sort`, `description`, `status`, `dict_id`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (659457929665052709, '小程序', 'xcx', '#7930AD', 999, NULL, 1, 4, 1, '2024-12-17 18:10:23', NULL, NULL); --- 插入客户端数据 -INSERT INTO `sys_client` (`id`, `client_id`, `client_key`, `client_secret`, `auth_type`, `client_type`, `active_timeout`, `timeout`, `status`, `create_user`, `create_time`, `update_user`, `update_time`) VALUES (1, 'ef51c9a3e9046c4f2ea45142c8a8344a', 'pc', 'dd77ab1e353a027e0d60ce3b151e8642', '[\"account\", \"socialAuth\", \"email\", \"phone\"]', 'pc', 1800, 86400, 1, 1, now(), 1, '2024-12-25 17:41:36'); - - +(1, 'ef51c9a3e9046c4f2ea45142c8a8344a', 'pc', 'dd77ab1e353a027e0d60ce3b151e8642', '[\"ACCOUNT\", \"EMAIL\", \"PHONE\", \"SOCIAL\"]', 'PC', 1800, 86400, 1, 1, NOW()); diff --git a/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql b/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql index 69fac008..afebf7ca 100644 --- a/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql +++ b/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql @@ -300,14 +300,14 @@ CREATE TABLE IF NOT EXISTS `sys_client` ( `client_id` varchar(50) NOT NULL COMMENT '客户端ID', `client_key` varchar(255) NOT NULL COMMENT '客户端Key', `client_secret` varchar(255) NOT NULL COMMENT '客户端秘钥', - `auth_type` json DEFAULT NULL COMMENT '授权类型', - `client_type` varchar(50) DEFAULT NULL COMMENT '客户端类型', + `auth_type` json DEFAULT NULL COMMENT '认证类型', + `client_type` varchar(50) NOT NULL COMMENT '客户端类型', `active_timeout` int DEFAULT '-1' COMMENT 'Token最低活跃频率(-1为不限制)', `timeout` int DEFAULT '2592000' COMMENT 'Token有效期(默认30天,单位:秒)', - `status` tinyint(1) UNSIGNED NOT NULL COMMENT '状态(1:启用;2:禁用)', + `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', `create_user` bigint(20) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL COMMENT '创建时间', `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', `update_time` datetime DEFAULT NULL COMMENT '修改时间', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户端管理'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户端表'; diff --git a/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql b/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql index b5d2f543..c164bae1 100644 --- a/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql +++ b/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql @@ -1,6 +1,6 @@ -- liquibase formatted sql --- changeset Charles7c:1 +-- changeset charles7c:1 -- comment 初始化表数据 -- 初始化默认菜单 INSERT INTO "sys_menu" diff --git a/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql b/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql index ee736ce2..25075ec5 100644 --- a/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql +++ b/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql @@ -1,6 +1,6 @@ -- liquibase formatted sql --- changeset Charles7c:1 +-- changeset charles7c:1 -- comment 初始化表结构 CREATE TABLE IF NOT EXISTS "sys_menu" ( "id" int8 NOT NULL,