From 2a22d06da69ab70d7f39f81d839970c323a784ac Mon Sep 17 00:00:00 2001 From: luoqiz Date: Fri, 24 Apr 2026 14:40:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(system/client):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=8F=8Ctoken=E8=AE=A4=E8=AF=81=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/changelog/db.changelog-master.yaml | 6 +- .../mysql/V4.2.0/v4.2.0_1_change.sql | 15 +++++ .../postgresql/V4.2.0/v4.2.0_1_change.sql | 21 +++++++ .../admin/auth/AbstractLoginHandler.java | 13 ++--- .../top/continew/admin/auth/LoginHandler.java | 41 ++++++++++++++ .../admin/auth/constant/AuthConstants.java | 5 ++ .../admin/auth/controller/AuthController.java | 12 +++- .../auth/model/resp/DoubleTokenLoginResp.java | 55 +++++++++++++++++++ .../admin/auth/model/resp/LoginResp.java | 10 +--- .../auth/model/resp/SingleTokenLoginResp.java | 44 +++++++++++++++ .../admin/auth/service/AuthService.java | 8 +++ .../auth/service/impl/AuthServiceImpl.java | 41 ++++++++++++-- .../admin/system/model/entity/ClientDO.java | 10 ++++ .../admin/system/model/req/ClientReq.java | 13 +++++ .../admin/system/model/resp/ClientResp.java | 14 +++++ 15 files changed, 285 insertions(+), 23 deletions(-) create mode 100644 continew-server/src/main/resources/db/changelog/mysql/V4.2.0/v4.2.0_1_change.sql create mode 100644 continew-server/src/main/resources/db/changelog/postgresql/V4.2.0/v4.2.0_1_change.sql create mode 100644 continew-system/src/main/java/top/continew/admin/auth/model/resp/DoubleTokenLoginResp.java create mode 100644 continew-system/src/main/java/top/continew/admin/auth/model/resp/SingleTokenLoginResp.java diff --git a/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml b/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml index 92ef3a642..b3fea44a0 100644 --- a/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml @@ -11,6 +11,8 @@ databaseChangeLog: file: db/changelog/mysql/plugin/plugin_schedule.sql - include: file: db/changelog/mysql/plugin/plugin_generator.sql + - includeAll: + path: db/changelog/mysql/V4.2.0 # PostgreSQL # - include: # file: db/changelog/postgresql/main_table.sql @@ -23,4 +25,6 @@ databaseChangeLog: # - include: # file: db/changelog/postgresql/plugin/plugin_schedule.sql # - include: -# file: db/changelog/postgresql/plugin/plugin_generator.sql \ No newline at end of file +# file: db/changelog/postgresql/plugin/plugin_generator.sql +# - includeAll: +# path: db/changelog/postgresql/V4.2.0 \ No newline at end of file diff --git a/continew-server/src/main/resources/db/changelog/mysql/V4.2.0/v4.2.0_1_change.sql b/continew-server/src/main/resources/db/changelog/mysql/V4.2.0/v4.2.0_1_change.sql new file mode 100644 index 000000000..d2769217c --- /dev/null +++ b/continew-server/src/main/resources/db/changelog/mysql/V4.2.0/v4.2.0_1_change.sql @@ -0,0 +1,15 @@ +-- liquibase formatted sql + +-- changeset luoqiz:4.2.0-1 +-- comment sys_client 客户端表更新 +-- sys_client 添加双token列 +ALTER TABLE `sys_client` + ADD COLUMN `is_enable_refresh_token` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用refresh token (true: 启用; false: 禁用)' AFTER `timeout`, +ADD COLUMN `refresh_token_timeout` bigint NULL DEFAULT 2592000 COMMENT 'Refresh token有效期(单位:秒; 值必须大于0,否则取token的有效时长)' AFTER `is_enable_refresh_token`; + +-- 初始化客户端数据 +INSERT INTO `sys_client` +(`id`, `client_id`, `client_type`, `auth_type`, `active_timeout`, `timeout`, `status`, `create_user`, `create_time`, + `is_enable_refresh_token`, `refresh_token_timeout`) +VALUES (2, 'ef51c9a3e9046c4f2ea45142c8a8344b', 'XCX', '["ACCOUNT", "EMAIL", "PHONE", "SOCIAL"]', 1800, 86400, 1, 1, + NOW(), b'1', 2592000); diff --git a/continew-server/src/main/resources/db/changelog/postgresql/V4.2.0/v4.2.0_1_change.sql b/continew-server/src/main/resources/db/changelog/postgresql/V4.2.0/v4.2.0_1_change.sql new file mode 100644 index 000000000..f16f6e159 --- /dev/null +++ b/continew-server/src/main/resources/db/changelog/postgresql/V4.2.0/v4.2.0_1_change.sql @@ -0,0 +1,21 @@ +-- liquibase formatted sql + +-- changeset luoqiz:4.2.0-1 +-- comment sys_client 客户端表更新 +-- sys_client 添加双token列 +ALTER TABLE "public"."sys_client" + ADD COLUMN "is_enable_refresh_token" bool NOT NULL DEFAULT false, + ADD COLUMN "refresh_token_timeout" int8 DEFAULT 2592000; + +COMMENT +ON COLUMN "public"."sys_client"."is_enable_refresh_token" IS '是否启用refresh token (true: 启用; false: 禁用)'; + +COMMENT +ON COLUMN "public"."sys_client"."refresh_token_timeout" IS 'Refresh token有效期(单位:秒; 值必须大于0,否则取token的有效时长)'; + +-- 初始化客户端数据 +INSERT INTO "sys_client" +("id", "client_id", "client_type", "auth_type", "active_timeout", "timeout", "status", "create_user", "create_time", + "is_enable_refresh_token", "refresh_token_timeout") +VALUES (2, 'ef51c9a3e9046c4f2ea45142c8a8344b', 'XCX', '["ACCOUNT", "EMAIL", "PHONE", "SOCIAL"]', 1800, 86400, 1, 1, + NOW(), true, 2592000); diff --git a/continew-system/src/main/java/top/continew/admin/auth/AbstractLoginHandler.java b/continew-system/src/main/java/top/continew/admin/auth/AbstractLoginHandler.java index 6a34278bf..32df94081 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/AbstractLoginHandler.java +++ b/continew-system/src/main/java/top/continew/admin/auth/AbstractLoginHandler.java @@ -16,7 +16,6 @@ package top.continew.admin.auth; -import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.parameter.SaLoginParameter; import cn.dev33.satoken.stp.parameter.enums.SaLogoutMode; import cn.dev33.satoken.stp.parameter.enums.SaReplacedRange; @@ -25,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; +import top.continew.admin.auth.constant.AuthConstants; import top.continew.admin.auth.model.req.LoginReq; import top.continew.admin.auth.model.resp.LoginResp; import top.continew.admin.common.context.RoleContext; @@ -46,6 +46,7 @@ import top.continew.starter.extension.tenant.util.TenantUtils; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -136,13 +137,11 @@ protected LoginResp authenticate(UserDO user, ClientResp client) { userContext.setClientId(client.getClientId()); userContext.setTenantId(tenantId); // 登录并缓存用户信息 - StpUtil.login(userContext.getId(), loginParameter.setExtraData(BeanUtil - .beanToMap(new UserExtraContext(ServletUtils.getRequest())))); + Map extraData = BeanUtil.beanToMap(new UserExtraContext(ServletUtils.getRequest())); + extraData.put(AuthConstants.LOGIN_USER, userContext); + loginParameter.setExtraData(extraData); UserContextHolder.setContext(userContext); - return LoginResp.builder() - .token(StpUtil.getTokenValue()) - .tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null) - .build(); + return LoginHandler.buildLoginResp(loginParameter, userContext, client); } /** diff --git a/continew-system/src/main/java/top/continew/admin/auth/LoginHandler.java b/continew-system/src/main/java/top/continew/admin/auth/LoginHandler.java index f5a74936b..0bde09923 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/LoginHandler.java +++ b/continew-system/src/main/java/top/continew/admin/auth/LoginHandler.java @@ -16,11 +16,18 @@ package top.continew.admin.auth; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.dev33.satoken.temp.SaTempUtil; import jakarta.servlet.http.HttpServletRequest; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.LoginReq; +import top.continew.admin.auth.model.resp.DoubleTokenLoginResp; import top.continew.admin.auth.model.resp.LoginResp; +import top.continew.admin.auth.model.resp.SingleTokenLoginResp; +import top.continew.admin.common.context.UserContext; import top.continew.admin.system.model.resp.ClientResp; +import top.continew.starter.extension.tenant.context.TenantContextHolder; /** * 登录处理器 @@ -65,4 +72,38 @@ public interface LoginHandler { * @return 认证类型 */ AuthTypeEnum getAuthType(); + + /** + * 构建登录信息 + * + * @param loginParameter 登录的参数 + * @param userContext 用户上下文信息 + * @param client 客户端信息 + * @return + */ + static LoginResp buildLoginResp(SaLoginParameter loginParameter, UserContext userContext, ClientResp client) { + StpUtil.login(userContext.getId(), loginParameter); + if (Boolean.TRUE.equals(client.getIsEnableRefreshToken())) { + // 刷新令牌设置的有效时长 + long refreshExpiresIn = (client.getRefreshTokenTimeout() != null && client.getRefreshTokenTimeout() > 0L) + ? client.getRefreshTokenTimeout() : client.getTimeout(); + String refreshToken = SaTempUtil.createToken(userContext.getId(), refreshExpiresIn, false); + // 将生成的token保存一份,方便刷新token时删除先前的token + loginParameter.setToken(StpUtil.getTokenValue()); + SaTempUtil.saveToken(refreshToken, loginParameter, refreshExpiresIn); + return DoubleTokenLoginResp.builder() + .accessToken(StpUtil.getTokenValue()) + .accessExpiresIn(StpUtil.getTokenTimeout()) + .refreshToken(refreshToken) + .refreshExpiresIn(refreshExpiresIn) + .tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null) + .build(); + } else { + return SingleTokenLoginResp.builder() + .token(StpUtil.getTokenValue()) + .expiresIn(StpUtil.getTokenTimeout()) + .tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null) + .build(); + } + } } \ No newline at end of file diff --git a/continew-system/src/main/java/top/continew/admin/auth/constant/AuthConstants.java b/continew-system/src/main/java/top/continew/admin/auth/constant/AuthConstants.java index 37c4de732..b8342357b 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/constant/AuthConstants.java +++ b/continew-system/src/main/java/top/continew/admin/auth/constant/AuthConstants.java @@ -34,6 +34,11 @@ public class AuthConstants { */ public static final String LOGOUT_URI = "/auth/logout"; + /** + * Map 存储登录用户信息时的 key 值 + */ + public static final String LOGIN_USER = "loginUser"; + private AuthConstants() { } } diff --git a/continew-system/src/main/java/top/continew/admin/auth/controller/AuthController.java b/continew-system/src/main/java/top/continew/admin/auth/controller/AuthController.java index ee268a865..ab709e124 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/controller/AuthController.java +++ b/continew-system/src/main/java/top/continew/admin/auth/controller/AuthController.java @@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; @@ -72,6 +73,13 @@ public LoginResp login(@RequestBody @Valid LoginReq req, HttpServletRequest requ return authService.login(req, request); } + @SaIgnore + @Operation(summary = "刷新token", description = "刷新token") + @PostMapping("/refreshToken") + public LoginResp refreshToken(@RequestParam("refreshToken") @NotBlank String refreshToken) { + return authService.refreshToken(refreshToken); + } + @Operation(summary = "登出", description = "注销用户的当前登录") @Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER) @PostMapping("/logout") @@ -88,8 +96,8 @@ public Object logout() { public SocialAuthAuthorizeResp authorize(@PathVariable @EnumValue(value = SocialSourceEnum.class, message = "第三方平台无效") String source) { AuthRequest authRequest = authRequestFactory.getAuthRequest(source); return SocialAuthAuthorizeResp.builder() - .authorizeUrl(authRequest.authorize(AuthStateUtils.createState())) - .build(); + .authorizeUrl(authRequest.authorize(AuthStateUtils.createState())) + .build(); } @Log(ignore = true) diff --git a/continew-system/src/main/java/top/continew/admin/auth/model/resp/DoubleTokenLoginResp.java b/continew-system/src/main/java/top/continew/admin/auth/model/resp/DoubleTokenLoginResp.java new file mode 100644 index 000000000..ec83e9eb5 --- /dev/null +++ b/continew-system/src/main/java/top/continew/admin/auth/model/resp/DoubleTokenLoginResp.java @@ -0,0 +1,55 @@ +/* + * 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.model.resp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +/** + * 双token模式 + */ +@Data +@SuperBuilder +@EqualsAndHashCode(callSuper = true) +public class DoubleTokenLoginResp extends LoginResp { + + /** + * 访问令牌 + */ + @Schema(description = "访问令牌", example = "eyJ0eXAiOiJlV1QiLCJhbGciqiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb29pbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiSjd4SUljYnU5cmNwU09vQ3Uyc1ND1BYYTYycFRjcjAifQ.KUPOYm-2wfuLUSfEEAbpGE527fzmkAJG7sMNcQ0pUZ8") + private String accessToken; + + /** + * 刷新令牌 + */ + @Schema(description = "刷新令牌", example = "12a5c5e1f87d4b4db614c6229c2c8916") + private String refreshToken; + + /** + * 访问令牌有效时长(秒) + */ + @Schema(description = "访问令牌有效时长(秒)", example = "1800") + private Long accessExpiresIn; + + /** + * 刷新令牌有效时长(秒) + */ + @Schema(description = "刷新令牌有效时长(秒)", example = "2592000") + private Long refreshExpiresIn; +} diff --git a/continew-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java b/continew-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java index 0f329a5a7..d5dea66b6 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java +++ b/continew-system/src/main/java/top/continew/admin/auth/model/resp/LoginResp.java @@ -17,8 +17,8 @@ package top.continew.admin.auth.model.resp; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; import lombok.Data; +import lombok.experimental.SuperBuilder; import java.io.Serial; import java.io.Serializable; @@ -30,19 +30,13 @@ * @since 2022/12/21 20:42 */ @Data -@Builder +@SuperBuilder @Schema(description = "登录响应参数") public class LoginResp implements Serializable { @Serial private static final long serialVersionUID = 1L; - /** - * 令牌 - */ - @Schema(description = "令牌", example = "eyJ0eXAiOiJlV1QiLCJhbGciqiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb29pbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiSjd4SUljYnU5cmNwU09vQ3Uyc1ND1BYYTYycFRjcjAifQ.KUPOYm-2wfuLUSfEEAbpGE527fzmkAJG7sMNcQ0pUZ8") - private String token; - /** * 租户 ID */ diff --git a/continew-system/src/main/java/top/continew/admin/auth/model/resp/SingleTokenLoginResp.java b/continew-system/src/main/java/top/continew/admin/auth/model/resp/SingleTokenLoginResp.java new file mode 100644 index 000000000..4a86ee5dd --- /dev/null +++ b/continew-system/src/main/java/top/continew/admin/auth/model/resp/SingleTokenLoginResp.java @@ -0,0 +1,44 @@ +/* + * 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.model.resp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +/** + * 单token模式,只有访问的token + */ +@Data +@SuperBuilder +@EqualsAndHashCode(callSuper = true) +public class SingleTokenLoginResp extends LoginResp { + + /** + * 访问令牌 + */ + @Schema(description = "访问令牌", example = "eyJ0eXAiOiJlV1QiLCJhbGciqiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb29pbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiSjd4SUljYnU5cmNwU09vQ3Uyc1ND1BYYTYycFRjcjAifQ.KUPOYm-2wfuLUSfEEAbpGE527fzmkAJG7sMNcQ0pUZ8") + private String token; + + /** + * 有效时长(秒) + */ + @Schema(description = "有效时长(秒)", example = "8600") + private Long expiresIn; + +} diff --git a/continew-system/src/main/java/top/continew/admin/auth/service/AuthService.java b/continew-system/src/main/java/top/continew/admin/auth/service/AuthService.java index 3b61fc290..af7fee563 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/service/AuthService.java +++ b/continew-system/src/main/java/top/continew/admin/auth/service/AuthService.java @@ -47,4 +47,12 @@ public interface AuthService { * @return 路由树 */ List buildRouteTree(Long userId); + + /** + * 刷新token + * + * @param refreshToken 原认证的 Refresh Token + * @return 登录响应参数 + */ + LoginResp refreshToken(String refreshToken); } diff --git a/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java b/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java index 2111209fd..925aca3c2 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java @@ -16,6 +16,9 @@ package top.continew.admin.auth.service.impl; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.dev33.satoken.temp.SaTempUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.tree.Tree; @@ -26,12 +29,16 @@ import org.springframework.stereotype.Service; import top.continew.admin.auth.LoginHandler; import top.continew.admin.auth.LoginHandlerFactory; +import top.continew.admin.auth.constant.AuthConstants; import top.continew.admin.auth.enums.AuthTypeEnum; import top.continew.admin.auth.model.req.LoginReq; 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.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.constant.SystemConstants; import top.continew.admin.system.enums.MenuTypeEnum; @@ -40,14 +47,13 @@ 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.exception.BusinessException; +import top.continew.starter.core.util.ServletUtils; import top.continew.starter.core.util.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; +import java.util.*; /** * 认证业务实现 @@ -73,7 +79,7 @@ public LoginResp login(LoginReq req, HttpServletRequest request) { ValidationUtils.throwIfNull(client, "客户端不存在"); ValidationUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(client.getStatus()), "客户端已禁用"); ValidationUtils.throwIf(!client.getAuthType().contains(authType.getValue()), "该客户端暂未授权 [{}] 认证", authType - .getDescription()); + .getDescription()); // 获取处理器 LoginHandler loginHandler = loginHandlerFactory.getHandler(authType); // 登录前置处理 @@ -123,4 +129,29 @@ public List buildRouteTree(Long userId) { }); return BeanUtil.copyToList(treeList, RouteResp.class); } + + @Override + public LoginResp refreshToken(String refreshToken) { + Object refreshTokenInfo = SaTempUtil.parseToken(refreshToken); + if (refreshTokenInfo == null) { + throw new BusinessException("无效的Refresh Token"); + } + // 获取登录时设置的参数 + SaLoginParameter loginParameter = (SaLoginParameter) refreshTokenInfo; + // 替换登录的 UserContextHolder 为最新的 + UserContext oldUserContext = (UserContext) loginParameter.getExtra(AuthConstants.LOGIN_USER); + UserContext userContext = UserContextHolder.getContext(oldUserContext.getId()); + loginParameter.setExtra(AuthConstants.LOGIN_USER, userContext); + + ClientResp client = clientService.getByClientId(oldUserContext.getClientId()); + String oldToken = loginParameter.getToken(); + LoginResp loginResp = LoginHandler.buildLoginResp(loginParameter, userContext, client); + if (oldToken != null) { + // 删除原先的 Token + StpUtil.kickoutByTokenValue(oldToken); + } + // 删除原先的 Refresh token + SaTempUtil.deleteToken(refreshToken); + return loginResp; + } } diff --git a/continew-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java b/continew-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java index 38048328f..1540671e7 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/entity/ClientDO.java @@ -68,6 +68,16 @@ public class ClientDO extends BaseDO { */ private Long timeout; + /** + * 是否启用 Refresh Token + */ + private Boolean isEnableRefreshToken; + + /** + * Refresh Token 有效期(单位:秒,默认 2,592,000) + */ + private Long refreshTokenTimeout; + /** * 是否允许同一账号多地同时登录(true:允许;false:新登录挤掉旧登录) */ diff --git a/continew-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java b/continew-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java index 18e7bcce9..33f521ce2 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/req/ClientReq.java @@ -76,6 +76,19 @@ public class ClientReq implements Serializable { @NotNull(message = "Token 有效期不能为空") private Long timeout; + /** + * 是否启用Refresh Token + */ + @Schema(description = "是否启用 Refresh Token", example = "false") + @NotNull(message = "是否启用 Refresh Token 不能为空") + private Boolean isEnableRefreshToken; + + /** + * Refresh Token 有效期(单位:秒; 小于0,则和 Token 有效期相同) + */ + @Schema(description = "Refresh Token 有效期(单位:秒; 小于0,则和 Token 有效期相同)", example = "2592000") + private Long refreshTokenTimeout; + /** * 是否允许同一账号多地同时登录(true:允许;false:新登录挤掉旧登录) */ diff --git a/continew-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java b/continew-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java index aa454665b..d689efbb1 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java @@ -83,6 +83,20 @@ public class ClientResp extends BaseDetailResp { @ExcelProperty(value = "Token 有效期", order = 7) private Long timeout; + /** + * 是否启用 Refresh Token + */ + @Schema(description = "是否启用 Refresh Token", example = "false") + @ExcelProperty(value = "是否启用 Refresh Token", order = 7) + private Boolean isEnableRefreshToken; + + /** + * Refresh Token 有效期(单位:秒; 小于0,则和 Token 有效期相同) + */ + @Schema(description = "Refresh Token 有效期(单位:秒; 小于0,则和 Token 有效期相同)", example = "2592000") + @ExcelProperty(value = "Refresh Token 有效期", order = 7) + private Long refreshTokenTimeout; + /** * 是否允许同一账号多地同时登录(true:允许;false:新登录挤掉旧登录) */