From 79ea39dd078639b4e137d576f3d7820bb6c24d0a Mon Sep 17 00:00:00 2001 From: Charles7c Date: Thu, 10 Oct 2024 22:33:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E7=99=BB=E5=BD=95=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=EF=BC=88=E7=BA=BF=E7=A8=8B=E7=BA=A7=E5=AD=98?= =?UTF-8?q?=E5=82=A8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...aultDataPermissionUserContextProvider.java | 14 +- .../mybatis/MyBatisPlusMetaObjectHandler.java | 8 +- .../websocket/WebSocketClientServiceImpl.java | 10 +- .../admin/common/constant/CacheConstants.java | 5 - .../RoleDTO.java => context/RoleContext.java} | 6 +- .../UserContext.java} | 66 ++----- .../common/context/UserContextHolder.java | 185 ++++++++++++++++++ .../common/context/UserExtraContext.java | 77 ++++++++ .../admin/common/util/helper/LoginHelper.java | 152 -------------- .../admin/auth/service/OnlineUserService.java | 3 +- .../auth/service/impl/LoginServiceImpl.java | 23 ++- .../service/impl/OnlineUserServiceImpl.java | 104 +++++----- .../system/config/file/FileRecorderImpl.java | 4 +- .../admin/system/mapper/UserRoleMapper.java | 13 -- .../system/model/resp/UserDetailResp.java | 6 +- .../admin/system/model/resp/UserResp.java | 4 +- .../admin/system/service/RoleService.java | 4 +- .../admin/system/service/UserRoleService.java | 8 + .../system/service/impl/RoleServiceImpl.java | 26 +-- .../service/impl/UserRoleServiceImpl.java | 19 +- .../system/service/impl/UserServiceImpl.java | 23 +-- .../satoken/SaExtensionInterceptor.java | 62 ++++++ .../config/satoken/SaTokenConfiguration.java | 12 +- .../config/satoken/SaTokenPermissionImpl.java | 12 +- .../admin/controller/auth/AuthController.java | 16 +- .../controller/system/MessageController.java | 6 +- .../system/UserCenterController.java | 18 +- 27 files changed, 523 insertions(+), 363 deletions(-) rename continew-admin-common/src/main/java/top/continew/admin/common/{model/dto/RoleDTO.java => context/RoleContext.java} (90%) rename continew-admin-common/src/main/java/top/continew/admin/common/{model/dto/LoginUser.java => context/UserContext.java} (76%) create mode 100644 continew-admin-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java create mode 100644 continew-admin-common/src/main/java/top/continew/admin/common/context/UserExtraContext.java delete mode 100644 continew-admin-common/src/main/java/top/continew/admin/common/util/helper/LoginHelper.java create mode 100644 continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaExtensionInterceptor.java diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/DefaultDataPermissionUserContextProvider.java b/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/DefaultDataPermissionUserContextProvider.java index 5b0dd7e8..c084ac65 100644 --- a/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/DefaultDataPermissionUserContextProvider.java +++ b/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/DefaultDataPermissionUserContextProvider.java @@ -17,8 +17,7 @@ package top.continew.admin.common.config.mybatis; import cn.hutool.core.convert.Convert; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContextHolder; import top.continew.starter.extension.datapermission.enums.DataScope; import top.continew.starter.extension.datapermission.filter.DataPermissionUserContextProvider; import top.continew.starter.extension.datapermission.model.RoleContext; @@ -36,17 +35,16 @@ public class DefaultDataPermissionUserContextProvider implements DataPermissionU @Override public boolean isFilter() { - LoginUser loginUser = LoginHelper.getLoginUser(); - return !loginUser.isAdmin(); + return !UserContextHolder.isAdmin(); } @Override public UserContext getUserContext() { - LoginUser loginUser = LoginHelper.getLoginUser(); + top.continew.admin.common.context.UserContext context = UserContextHolder.getContext(); UserContext userContext = new UserContext(); - userContext.setUserId(Convert.toStr(loginUser.getId())); - userContext.setDeptId(Convert.toStr(loginUser.getDeptId())); - userContext.setRoles(loginUser.getRoles() + userContext.setUserId(Convert.toStr(context.getId())); + userContext.setDeptId(Convert.toStr(context.getDeptId())); + userContext.setRoles(context.getRoles() .stream() .map(r -> new RoleContext(Convert.toStr(r.getId()), DataScope.valueOf(r.getDataScope().name()))) .collect(Collectors.toSet())); diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java b/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java index 79c87cb2..ed0d0b7d 100644 --- a/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java +++ b/continew-admin-common/src/main/java/top/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java @@ -19,9 +19,8 @@ package top.continew.admin.common.config.mybatis; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContextHolder; import top.continew.starter.core.exception.BusinessException; -import top.continew.starter.core.util.ExceptionUtils; import top.continew.starter.extension.crud.model.entity.BaseDO; import java.time.LocalDateTime; @@ -62,7 +61,7 @@ public class MyBatisPlusMetaObjectHandler implements MetaObjectHandler { if (null == metaObject) { return; } - Long createUser = ExceptionUtils.exToNull(LoginHelper::getUserId); + Long createUser = UserContextHolder.getUserId(); LocalDateTime createTime = LocalDateTime.now(); if (metaObject.getOriginalObject() instanceof BaseDO baseDO) { // 继承了 BaseDO 的类,填充创建信息字段 @@ -89,8 +88,7 @@ public class MyBatisPlusMetaObjectHandler implements MetaObjectHandler { if (null == metaObject) { return; } - - Long updateUser = LoginHelper.getUserId(); + Long updateUser = UserContextHolder.getUserId(); LocalDateTime updateTime = LocalDateTime.now(); if (metaObject.getOriginalObject() instanceof BaseDO baseDO) { // 继承了 BaseDO 的类,填充修改信息 diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketClientServiceImpl.java b/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketClientServiceImpl.java index 751567a7..02d466cd 100644 --- a/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketClientServiceImpl.java +++ b/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketClientServiceImpl.java @@ -16,11 +16,11 @@ package top.continew.admin.common.config.websocket; +import cn.dev33.satoken.stp.StpUtil; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.stereotype.Component; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.starter.core.exception.BusinessException; import top.continew.starter.messaging.websocket.core.WebSocketClientService; /** @@ -36,7 +36,9 @@ public class WebSocketClientServiceImpl implements WebSocketClientService { public String getClientId(ServletServerHttpRequest request) { HttpServletRequest servletRequest = request.getServletRequest(); String token = servletRequest.getParameter("token"); - LoginUser loginUser = LoginHelper.getLoginUser(token); - return loginUser.getToken(); + if (null == StpUtil.getLoginIdByToken(token)) { + throw new BusinessException("登录已过期,请重新登录"); + } + return token; } } diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java b/continew-admin-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java index 697de7c7..e625d854 100644 --- a/continew-admin-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java +++ b/continew-admin-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java @@ -31,11 +31,6 @@ public class CacheConstants { */ public static final String DELIMITER = StringConstants.COLON; - /** - * 登录用户键 - */ - public static final String LOGIN_USER_KEY = "LOGIN_USER"; - /** * 验证码键前缀 */ diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/RoleDTO.java b/continew-admin-common/src/main/java/top/continew/admin/common/context/RoleContext.java similarity index 90% rename from continew-admin-common/src/main/java/top/continew/admin/common/model/dto/RoleDTO.java rename to continew-admin-common/src/main/java/top/continew/admin/common/context/RoleContext.java index 212c92a8..ed628f40 100644 --- a/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/RoleDTO.java +++ b/continew-admin-common/src/main/java/top/continew/admin/common/context/RoleContext.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package top.continew.admin.common.model.dto; +package top.continew.admin.common.context; import lombok.Data; import top.continew.admin.common.enums.DataScopeEnum; @@ -23,13 +23,13 @@ import java.io.Serial; import java.io.Serializable; /** - * 角色信息 + * 角色上下文 * * @author Charles7c * @since 2023/3/7 22:08 */ @Data -public class RoleDTO implements Serializable { +public class RoleContext implements Serializable { @Serial private static final long serialVersionUID = 1L; diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/LoginUser.java b/continew-admin-common/src/main/java/top/continew/admin/common/context/UserContext.java similarity index 76% rename from continew-admin-common/src/main/java/top/continew/admin/common/model/dto/LoginUser.java rename to continew-admin-common/src/main/java/top/continew/admin/common/context/UserContext.java index 76b24cf8..4505b41f 100644 --- a/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/LoginUser.java +++ b/continew-admin-common/src/main/java/top/continew/admin/common/context/UserContext.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package top.continew.admin.common.model.dto; +package top.continew.admin.common.context; import cn.hutool.core.collection.CollUtil; import lombok.Data; @@ -28,14 +28,14 @@ import java.util.Set; import java.util.stream.Collectors; /** - * 登录用户信息 + * 用户上下文 * * @author Charles7c - * @since 2022/12/24 13:01 + * @since 2024/10/9 20:29 */ @Data @NoArgsConstructor -public class LoginUser implements Serializable { +public class UserContext implements Serializable { @Serial private static final long serialVersionUID = 1L; @@ -55,6 +55,16 @@ public class LoginUser implements Serializable { */ private Long deptId; + /** + * 最后一次修改密码时间 + */ + private LocalDateTime pwdResetTime; + + /** + * 登录时系统设置的密码过期天数 + */ + private Integer passwordExpirationDays; + /** * 权限码集合 */ @@ -68,57 +78,17 @@ public class LoginUser implements Serializable { /** * 角色集合 */ - private Set roles; + private Set roles; - /** - * 令牌 - */ - private String token; - - /** - * IP - */ - private String ip; - - /** - * IP 归属地 - */ - private String address; - - /** - * 浏览器 - */ - private String browser; - - /** - * 操作系统 - */ - private String os; - - /** - * 登录时间 - */ - private LocalDateTime loginTime; - - /** - * 最后一次修改密码时间 - */ - private LocalDateTime pwdResetTime; - - /** - * 登录时系统设置的密码过期天数 - */ - private Integer passwordExpirationDays; - - public LoginUser(Set permissions, Set roles, Integer passwordExpirationDays) { + public UserContext(Set permissions, Set roles, Integer passwordExpirationDays) { this.permissions = permissions; this.setRoles(roles); this.passwordExpirationDays = passwordExpirationDays; } - public void setRoles(Set roles) { + public void setRoles(Set roles) { this.roles = roles; - this.roleCodes = roles.stream().map(RoleDTO::getCode).collect(Collectors.toSet()); + this.roleCodes = roles.stream().map(RoleContext::getCode).collect(Collectors.toSet()); } /** diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java b/continew-admin-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java new file mode 100644 index 00000000..b9578fe9 --- /dev/null +++ b/continew-admin-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java @@ -0,0 +1,185 @@ +/* + * 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.common.context; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.extra.spring.SpringUtil; +import top.continew.starter.core.util.ExceptionUtils; +import top.continew.starter.extension.crud.service.CommonUserService; + +import java.util.Optional; + +/** + * 用户上下文 Holder + * + * @author Charles7c + * @since 2022/12/24 12:58 + */ +public class UserContextHolder { + + private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); + private static final ThreadLocal EXTRA_CONTEXT_HOLDER = new ThreadLocal<>(); + + private UserContextHolder() { + } + + /** + * 设置上下文 + * + * @param context 上下文 + */ + public static void setContext(UserContext context) { + setContext(context, true); + } + + /** + * 设置上下文 + * + * @param context 上下文 + * @param isUpdate 是否更新 + */ + public static void setContext(UserContext context, boolean isUpdate) { + CONTEXT_HOLDER.set(context); + if (isUpdate) { + StpUtil.getSessionByLoginId(context.getId()).set(SaSession.USER, context); + } + } + + /** + * 获取上下文 + * + * @return 上下文 + */ + public static UserContext getContext() { + UserContext context = CONTEXT_HOLDER.get(); + if (null == context) { + context = StpUtil.getSession().getModel(SaSession.USER, UserContext.class); + CONTEXT_HOLDER.set(context); + } + return context; + } + + /** + * 获取指定用户的上下文 + * + * @param userId 用户 ID + * @return 上下文 + */ + public static UserContext getContext(Long userId) { + SaSession session = StpUtil.getSessionByLoginId(userId, false); + if (null == session) { + return null; + } + return session.getModel(SaSession.USER, UserContext.class); + } + + /** + * 设置额外上下文 + * + * @param context 额外上下文 + */ + public static void setExtraContext(UserExtraContext context) { + EXTRA_CONTEXT_HOLDER.set(context); + } + + /** + * 获取额外上下文 + * + * @return 额外上下文 + */ + public static UserExtraContext getExtraContext() { + UserExtraContext context = EXTRA_CONTEXT_HOLDER.get(); + if (null == context) { + context = getExtraContext(StpUtil.getTokenValue()); + EXTRA_CONTEXT_HOLDER.set(context); + } + return context; + } + + /** + * 获取额外上下文 + * + * @param token 令牌 + * @return 额外上下文 + */ + public static UserExtraContext getExtraContext(String token) { + UserExtraContext context = new UserExtraContext(); + context.setIp(Convert.toStr(StpUtil.getExtra(token, "ip"))); + context.setAddress(Convert.toStr(StpUtil.getExtra(token, "address"))); + context.setBrowser(Convert.toStr(StpUtil.getExtra(token, "browser"))); + context.setOs(Convert.toStr(StpUtil.getExtra(token, "os"))); + context.setLoginTime(Convert.toLocalDateTime(StpUtil.getExtra(token, "loginTime"))); + return context; + } + + /** + * 清除上下文 + */ + public static void clearContext() { + CONTEXT_HOLDER.remove(); + EXTRA_CONTEXT_HOLDER.remove(); + } + + /** + * 获取用户 ID + * + * @return 用户 ID + */ + public static Long getUserId() { + return Optional.ofNullable(getContext()).map(UserContext::getId).orElse(null); + } + + /** + * 获取用户名 + * + * @return 用户名 + */ + public static String getUsername() { + return Optional.ofNullable(getContext()).map(UserContext::getUsername).orElse(null); + } + + /** + * 获取用户昵称 + * + * @return 用户昵称 + */ + public static String getNickname() { + return getNickname(getUserId()); + } + + /** + * 获取用户昵称 + * + * @param userId 登录用户 ID + * @return 用户昵称 + */ + public static String getNickname(Long userId) { + return ExceptionUtils.exToNull(() -> SpringUtil.getBean(CommonUserService.class).getNicknameById(userId)); + } + + /** + * 是否为管理员 + * + * @return 是否为管理员 + */ + public static Boolean isAdmin() { + StpUtil.checkLogin(); + return getContext().isAdmin(); + } +} diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/context/UserExtraContext.java b/continew-admin-common/src/main/java/top/continew/admin/common/context/UserExtraContext.java new file mode 100644 index 00000000..3271a774 --- /dev/null +++ b/continew-admin-common/src/main/java/top/continew/admin/common/context/UserExtraContext.java @@ -0,0 +1,77 @@ +/* + * 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.common.context; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.Data; +import lombok.NoArgsConstructor; +import top.continew.starter.core.util.ExceptionUtils; +import top.continew.starter.core.util.IpUtils; +import top.continew.starter.web.util.ServletUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 用户额外上下文 + * + * @author Charles7c + * @since 2024/10/9 20:29 + */ +@Data +@NoArgsConstructor +public class UserExtraContext implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * IP + */ + private String ip; + + /** + * IP 归属地 + */ + private String address; + + /** + * 浏览器 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private LocalDateTime loginTime; + + public UserExtraContext(HttpServletRequest request) { + this.ip = JakartaServletUtil.getClientIP(request); + this.address = ExceptionUtils.exToNull(() -> IpUtils.getIpv4Address(this.ip)); + this.setBrowser(ServletUtils.getBrowser(request)); + this.setLoginTime(LocalDateTime.now()); + this.setOs(StrUtil.subBefore(ServletUtils.getOs(request), " or", false)); + } +} diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/util/helper/LoginHelper.java b/continew-admin-common/src/main/java/top/continew/admin/common/util/helper/LoginHelper.java deleted file mode 100644 index aa0bcc07..00000000 --- a/continew-admin-common/src/main/java/top/continew/admin/common/util/helper/LoginHelper.java +++ /dev/null @@ -1,152 +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.common.util.helper; - -import cn.dev33.satoken.context.SaHolder; -import cn.dev33.satoken.exception.NotLoginException; -import cn.dev33.satoken.session.SaSession; -import cn.dev33.satoken.stp.StpUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.servlet.JakartaServletUtil; -import cn.hutool.extra.spring.SpringUtil; -import jakarta.servlet.http.HttpServletRequest; -import top.continew.admin.common.constant.CacheConstants; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.starter.core.util.ExceptionUtils; -import top.continew.starter.core.util.IpUtils; -import top.continew.starter.extension.crud.service.CommonUserService; -import top.continew.starter.web.util.ServletUtils; -import top.continew.starter.web.util.SpringWebUtils; - -import java.time.LocalDateTime; - -/** - * 登录助手 - * - * @author Charles7c - * @author Lion Li(RuoYi-Vue-Plus) - * @since 2022/12/24 12:58 - */ -public class LoginHelper { - - private LoginHelper() { - } - - /** - * 用户登录并缓存用户信息 - * - * @param loginUser 登录用户信息 - * @return 令牌 - */ - public static String login(LoginUser loginUser) { - // 记录登录信息 - HttpServletRequest request = SpringWebUtils.getRequest(); - loginUser.setIp(JakartaServletUtil.getClientIP(request)); - loginUser.setAddress(ExceptionUtils.exToNull(() -> IpUtils.getIpv4Address(loginUser.getIp()))); - loginUser.setBrowser(ServletUtils.getBrowser(request)); - loginUser.setLoginTime(LocalDateTime.now()); - loginUser.setOs(StrUtil.subBefore(ServletUtils.getOs(request), " or", false)); - // 登录并缓存用户信息 - StpUtil.login(loginUser.getId()); - SaHolder.getStorage().set(CacheConstants.LOGIN_USER_KEY, loginUser); - String tokenValue = StpUtil.getTokenValue(); - loginUser.setToken(tokenValue); - StpUtil.getTokenSession().set(CacheConstants.LOGIN_USER_KEY, loginUser); - return tokenValue; - } - - /** - * 更新登录用户信息 - * - * @param loginUser - * 登录用户信息 - * @param token 令牌 - */ - public static void updateLoginUser(LoginUser loginUser, String token) { - SaHolder.getStorage().delete(CacheConstants.LOGIN_USER_KEY); - StpUtil.getTokenSessionByToken(token).set(CacheConstants.LOGIN_USER_KEY, loginUser); - } - - /** - * 获取登录用户信息 - * - * @return 登录用户信息 - * @throws NotLoginException 未登录异常 - */ - public static LoginUser getLoginUser() throws NotLoginException { - StpUtil.checkLogin(); - LoginUser loginUser = (LoginUser)SaHolder.getStorage().get(CacheConstants.LOGIN_USER_KEY); - if (null != loginUser) { - return loginUser; - } - SaSession tokenSession = StpUtil.getTokenSession(); - loginUser = (LoginUser)tokenSession.get(CacheConstants.LOGIN_USER_KEY); - SaHolder.getStorage().set(CacheConstants.LOGIN_USER_KEY, loginUser); - return loginUser; - } - - /** - * 根据 Token 获取登录用户信息 - * - * @param token 用户 Token - * @return 登录用户信息 - */ - public static LoginUser getLoginUser(String token) { - SaSession tokenSession = StpUtil.getStpLogic().getTokenSessionByToken(token, false); - if (null == tokenSession) { - return null; - } - return (LoginUser)tokenSession.get(CacheConstants.LOGIN_USER_KEY); - } - - /** - * 获取登录用户 ID - * - * @return 登录用户 ID - */ - public static Long getUserId() { - return getLoginUser().getId(); - } - - /** - * 获取登录用户名 - * - * @return 登录用户名 - */ - public static String getUsername() { - return getLoginUser().getUsername(); - } - - /** - * 获取登录用户昵称 - * - * @return 登录用户昵称 - */ - public static String getNickname() { - return getNickname(getUserId()); - } - - /** - * 获取登录用户昵称 - * - * @param userId 登录用户 ID - * @return 登录用户昵称 - */ - public static String getNickname(Long userId) { - return ExceptionUtils.exToNull(() -> SpringUtil.getBean(CommonUserService.class).getNicknameById(userId)); - } -} diff --git a/continew-admin-system/src/main/java/top/continew/admin/auth/service/OnlineUserService.java b/continew-admin-system/src/main/java/top/continew/admin/auth/service/OnlineUserService.java index 530efe12..3df02c14 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/auth/service/OnlineUserService.java +++ b/continew-admin-system/src/main/java/top/continew/admin/auth/service/OnlineUserService.java @@ -18,7 +18,6 @@ package top.continew.admin.auth.service; import top.continew.admin.auth.model.query.OnlineUserQuery; import top.continew.admin.auth.model.resp.OnlineUserResp; -import top.continew.admin.common.model.dto.LoginUser; import top.continew.starter.extension.crud.model.query.PageQuery; import top.continew.starter.extension.crud.model.resp.PageResp; @@ -48,7 +47,7 @@ public interface OnlineUserService { * @param query 查询条件 * @return 列表信息 */ - List list(OnlineUserQuery query); + List list(OnlineUserQuery query); /** * 查询 Token 最后活跃时间 diff --git a/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java index d040bad4..ea6357ab 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/LoginServiceImpl.java @@ -16,6 +16,7 @@ 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; @@ -39,11 +40,12 @@ 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.common.model.dto.LoginUser; -import top.continew.admin.common.model.dto.RoleDTO; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.admin.system.enums.MenuTypeEnum; import top.continew.admin.system.enums.MessageTemplateEnum; import top.continew.admin.system.enums.MessageTypeEnum; @@ -61,6 +63,7 @@ import top.continew.starter.core.util.validate.CheckUtils; import top.continew.starter.extension.crud.annotation.TreeField; import top.continew.starter.extension.crud.util.TreeUtils; import top.continew.starter.messaging.websocket.util.WebSocketUtils; +import top.continew.starter.web.util.SpringWebUtils; import java.time.Duration; import java.time.LocalDateTime; @@ -205,15 +208,19 @@ public class LoginServiceImpl implements LoginService { Long userId = user.getId(); CompletableFuture> permissionFuture = CompletableFuture.supplyAsync(() -> roleService .listPermissionByUserId(userId), threadPoolTaskExecutor); - CompletableFuture> roleFuture = CompletableFuture.supplyAsync(() -> roleService + CompletableFuture> roleFuture = CompletableFuture.supplyAsync(() -> roleService .listByUserId(userId), threadPoolTaskExecutor); CompletableFuture passwordExpirationDaysFuture = CompletableFuture.supplyAsync(() -> optionService .getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name())); CompletableFuture.allOf(permissionFuture, roleFuture, passwordExpirationDaysFuture); - LoginUser loginUser = new LoginUser(permissionFuture.join(), roleFuture.join(), passwordExpirationDaysFuture - .join()); - BeanUtil.copyProperties(user, loginUser); - return LoginHelper.login(loginUser); + 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(); } /** diff --git a/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java index 81ebc75c..fecd40a8 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java @@ -21,6 +21,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; @@ -28,17 +29,16 @@ import org.springframework.stereotype.Service; import top.continew.admin.auth.model.query.OnlineUserQuery; import top.continew.admin.auth.model.resp.OnlineUserResp; import top.continew.admin.auth.service.OnlineUserService; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContext; +import top.continew.admin.common.context.UserContextHolder; +import top.continew.admin.common.context.UserExtraContext; import top.continew.starter.core.constant.StringConstants; import top.continew.starter.extension.crud.model.query.PageQuery; import top.continew.starter.extension.crud.model.resp.PageResp; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Date; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * 在线用户业务实现 @@ -53,31 +53,43 @@ public class OnlineUserServiceImpl implements OnlineUserService { @Override @AutoOperate(type = OnlineUserResp.class, on = "list") public PageResp page(OnlineUserQuery query, PageQuery pageQuery) { - List loginUserList = this.list(query); - List list = BeanUtil.copyToList(loginUserList, OnlineUserResp.class); + List list = this.list(query); return PageResp.build(pageQuery.getPage(), pageQuery.getSize(), list); } @Override - public List list(OnlineUserQuery query) { - List loginUserList = new ArrayList<>(); - // 查询所有登录用户 + public List list(OnlineUserQuery query) { + List list = new ArrayList<>(); + // 查询所有在线 Token List tokenKeyList = StpUtil.searchTokenValue(StringConstants.EMPTY, 0, -1, false); - tokenKeyList.parallelStream().forEach(tokenKey -> { + Map> tokenMap = tokenKeyList.stream().filter(tokenKey -> { String token = StrUtil.subAfter(tokenKey, StringConstants.COLON, true); // 忽略已过期或失效 Token - if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < SaTokenDao.NEVER_EXPIRE) { - return; + return StpUtil.getStpLogic().getTokenActiveTimeoutByToken(token) >= SaTokenDao.NEVER_EXPIRE; + }) + .map(tokenKey -> StrUtil.subAfter(tokenKey, StringConstants.COLON, true)) + .collect(Collectors.groupingBy(token -> Convert.toLong(StpUtil.getLoginIdByToken(token)))); + // 过滤 Token + for (Map.Entry> entry : tokenMap.entrySet()) { + Long userId = entry.getKey(); + UserContext userContext = UserContextHolder.getContext(userId); + if (null == userContext || !this.isMatchNickname(query.getNickname(), userContext)) { + continue; } - // 检查是否符合查询条件 - LoginUser loginUser = LoginHelper.getLoginUser(token); - if (this.isMatchQuery(query, loginUser)) { - loginUserList.add(loginUser); - } - }); + List loginTimeList = query.getLoginTime(); + entry.getValue().parallelStream().forEach(token -> { + UserExtraContext extraContext = UserContextHolder.getExtraContext(token); + if (this.isMatchLoginTime(loginTimeList, extraContext.getLoginTime())) { + OnlineUserResp resp = BeanUtil.copyProperties(userContext, OnlineUserResp.class); + BeanUtil.copyProperties(extraContext, resp); + resp.setToken(token); + list.add(resp); + } + }); + } // 设置排序 - CollUtil.sort(loginUserList, Comparator.comparing(LoginUser::getLoginTime).reversed()); - return loginUserList; + CollUtil.sort(list, Comparator.comparing(OnlineUserResp::getLoginTime).reversed()); + return list; } @Override @@ -95,35 +107,31 @@ public class OnlineUserServiceImpl implements OnlineUserService { } /** - * 是否符合查询条件 + * 是否匹配昵称 * - * @param query 查询条件 - * @param loginUser 登录用户信息 - * @return 是否符合查询条件 + * @param nickname 昵称 + * @param userContext 用户上下文信息 + * @return 是否匹配昵称 */ - private boolean isMatchQuery(OnlineUserQuery query, LoginUser loginUser) { - boolean flag1 = true; - String nickname = query.getNickname(); - if (StrUtil.isNotBlank(nickname)) { - flag1 = StrUtil.contains(loginUser.getUsername(), nickname) || StrUtil.contains(LoginHelper - .getNickname(loginUser.getId()), nickname); + private boolean isMatchNickname(String nickname, UserContext userContext) { + if (StrUtil.isBlank(nickname)) { + return true; } - boolean flag2 = true; - List loginTime = query.getLoginTime(); - if (CollUtil.isNotEmpty(loginTime)) { - flag2 = DateUtil.isIn(DateUtil.date(loginUser.getLoginTime()).toJdkDate(), loginTime.get(0), loginTime - .get(1)); + return StrUtil.contains(userContext.getUsername(), nickname) || StrUtil.contains(UserContextHolder + .getNickname(userContext.getId()), nickname); + } + + /** + * 是否匹配登录时间 + * + * @param loginTimeList 登录时间列表 + * @param loginTime 登录时间 + * @return 是否匹配登录时间 + */ + private boolean isMatchLoginTime(List loginTimeList, LocalDateTime loginTime) { + if (CollUtil.isEmpty(loginTimeList)) { + return true; } - boolean flag3 = true; - Long userId = query.getUserId(); - if (null != userId) { - flag3 = userId.equals(loginUser.getId()); - } - boolean flag4 = true; - Long roleId = query.getRoleId(); - if (null != roleId) { - flag4 = loginUser.getRoles().stream().anyMatch(r -> r.getId().equals(roleId)); - } - return flag1 && flag2 && flag3 && flag4; + return DateUtil.isIn(DateUtil.date(loginTime).toJdkDate(), loginTimeList.get(0), loginTimeList.get(1)); } } diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java index f8394d84..99f2ef99 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/config/file/FileRecorderImpl.java @@ -26,7 +26,7 @@ import org.dromara.x.file.storage.core.FileInfo; import org.dromara.x.file.storage.core.recorder.FileRecorder; import org.dromara.x.file.storage.core.upload.FilePartInfo; import org.springframework.stereotype.Component; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.system.enums.FileTypeEnum; import top.continew.admin.system.mapper.FileMapper; import top.continew.admin.system.mapper.StorageMapper; @@ -66,7 +66,7 @@ public class FileRecorderImpl implements FileRecorder { StorageDO storage = (StorageDO)fileInfo.getAttr().get(ClassUtil.getClassName(StorageDO.class, false)); file.setStorageId(storage.getId()); file.setCreateTime(DateUtil.toLocalDateTime(fileInfo.getCreateTime())); - file.setUpdateUser(LoginHelper.getUserId()); + file.setUpdateUser(UserContextHolder.getUserId()); file.setUpdateTime(file.getCreateTime()); fileMapper.insert(file); return true; diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/mapper/UserRoleMapper.java b/continew-admin-system/src/main/java/top/continew/admin/system/mapper/UserRoleMapper.java index bb0b9c3c..42d092fa 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/mapper/UserRoleMapper.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/mapper/UserRoleMapper.java @@ -16,13 +16,9 @@ package top.continew.admin.system.mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; import top.continew.admin.system.model.entity.UserRoleDO; import top.continew.starter.data.mp.base.BaseMapper; -import java.util.List; - /** * 用户和角色 Mapper * @@ -30,13 +26,4 @@ import java.util.List; * @since 2023/2/13 23:13 */ public interface UserRoleMapper extends BaseMapper { - - /** - * 根据用户 ID 查询 - * - * @param userId 用户 ID - * @return 角色 ID 列表 - */ - @Select("SELECT role_id FROM sys_user_role WHERE user_id = #{userId}") - List selectRoleIdByUserId(@Param("userId") Long userId); } diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserDetailResp.java b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserDetailResp.java index 4d7fce2d..157b2404 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserDetailResp.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserDetailResp.java @@ -27,12 +27,12 @@ import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import top.continew.admin.common.constant.ContainerConstants; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.admin.common.enums.GenderEnum; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.admin.system.service.DeptService; -import top.continew.starter.file.excel.converter.ExcelBaseEnumConverter; import top.continew.starter.extension.crud.model.resp.BaseDetailResp; +import top.continew.starter.file.excel.converter.ExcelBaseEnumConverter; import top.continew.starter.file.excel.converter.ExcelListConverter; import top.continew.starter.security.crypto.annotation.FieldEncrypt; @@ -160,6 +160,6 @@ public class UserDetailResp extends BaseDetailResp { @Override public Boolean getDisabled() { - return this.getIsSystem() || Objects.equals(this.getId(), LoginHelper.getUserId()); + return this.getIsSystem() || Objects.equals(this.getId(), UserContextHolder.getUserId()); } } diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserResp.java b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserResp.java index a7062a55..52f5b18a 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserResp.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/UserResp.java @@ -21,9 +21,9 @@ import cn.crane4j.core.executor.handler.ManyToManyAssembleOperationHandler; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import top.continew.admin.common.constant.ContainerConstants; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.admin.common.enums.GenderEnum; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.starter.extension.crud.model.resp.BaseDetailResp; import top.continew.starter.security.mask.annotation.JsonMask; import top.continew.starter.security.mask.enums.MaskType; @@ -129,6 +129,6 @@ public class UserResp extends BaseDetailResp { @Override public Boolean getDisabled() { - return this.getIsSystem() || Objects.equals(this.getId(), LoginHelper.getUserId()); + return this.getIsSystem() || Objects.equals(this.getId(), UserContextHolder.getUserId()); } } diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/RoleService.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/RoleService.java index ef9ddb91..7a76f0b0 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/RoleService.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/RoleService.java @@ -16,7 +16,7 @@ package top.continew.admin.system.service; -import top.continew.admin.common.model.dto.RoleDTO; +import top.continew.admin.common.context.RoleContext; import top.continew.admin.system.model.entity.RoleDO; import top.continew.admin.system.model.query.RoleQuery; import top.continew.admin.system.model.req.RoleReq; @@ -66,7 +66,7 @@ public interface RoleService extends BaseService listByUserId(Long userId); + Set listByUserId(Long userId); /** * 根据角色编码查询 diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/UserRoleService.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/UserRoleService.java index 628723a6..5a17e1a6 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/UserRoleService.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/UserRoleService.java @@ -59,6 +59,14 @@ public interface UserRoleService { */ List listRoleIdByUserId(Long userId); + /** + * 根据角色 ID 查询 + * + * @param roleId 角色 ID + * @return 用户 ID 列表 + */ + List listUserIdByRoleId(Long roleId); + /** * 根据角色 ID 判断是否已被用户关联 * diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java index 058d6e64..d13009c4 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java @@ -26,15 +26,14 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import top.continew.admin.auth.model.query.OnlineUserQuery; import top.continew.admin.auth.service.OnlineUserService; import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.ContainerConstants; 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.enums.DataScopeEnum; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.admin.common.model.dto.RoleDTO; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.admin.system.mapper.RoleMapper; import top.continew.admin.system.model.entity.RoleDO; import top.continew.admin.system.model.query.RoleQuery; @@ -104,13 +103,14 @@ public class RoleServiceImpl extends BaseServiceImpl loginUserList = onlineUserService.list(query); - loginUserList.forEach(loginUser -> { - loginUser.setRoles(this.listByUserId(loginUser.getId())); - loginUser.setPermissions(this.listPermissionByUserId(loginUser.getId())); - LoginHelper.updateLoginUser(loginUser, loginUser.getToken()); + List userIdList = userRoleService.listUserIdByRoleId(id); + userIdList.parallelStream().forEach(userId -> { + UserContext userContext = UserContextHolder.getContext(userId); + if (null != userContext) { + userContext.setRoles(this.listByUserId(userId)); + userContext.setPermissions(this.listPermissionByUserId(userId)); + UserContextHolder.setContext(userContext); + } }); } } @@ -171,10 +171,10 @@ public class RoleServiceImpl extends BaseServiceImpl listByUserId(Long userId) { + public Set listByUserId(Long userId) { List roleIdList = userRoleService.listRoleIdByUserId(userId); List roleList = baseMapper.lambdaQuery().in(RoleDO::getId, roleIdList).list(); - return new HashSet<>(BeanUtil.copyToList(roleList, RoleDTO.class)); + return new HashSet<>(BeanUtil.copyToList(roleList, RoleContext.class)); } @Override diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java index f961769b..fb5b48f8 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java @@ -75,7 +75,24 @@ public class UserRoleServiceImpl implements UserRoleService { @Override @ContainerMethod(namespace = ContainerConstants.USER_ROLE_ID_LIST, type = MappingType.ORDER_OF_KEYS) public List listRoleIdByUserId(Long userId) { - return baseMapper.selectRoleIdByUserId(userId); + return baseMapper.lambdaQuery() + .select(UserRoleDO::getRoleId) + .eq(UserRoleDO::getUserId, userId) + .list() + .stream() + .map(UserRoleDO::getRoleId) + .toList(); + } + + @Override + public List listUserIdByRoleId(Long roleId) { + return baseMapper.lambdaQuery() + .select(UserRoleDO::getUserId) + .eq(UserRoleDO::getRoleId, roleId) + .list() + .stream() + .map(UserRoleDO::getUserId) + .toList(); } @Override diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java index 53038e93..814d2ff8 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java @@ -52,15 +52,14 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import top.continew.admin.auth.model.query.OnlineUserQuery; import top.continew.admin.auth.service.OnlineUserService; import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.SysConstants; +import top.continew.admin.common.context.UserContext; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.admin.common.enums.GenderEnum; -import top.continew.admin.common.model.dto.LoginUser; import top.continew.admin.common.util.SecureUtils; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.admin.system.mapper.UserMapper; import top.continew.admin.system.model.entity.DeptDO; import top.continew.admin.system.model.entity.RoleDO; @@ -310,7 +309,7 @@ public class UserServiceImpl extends BaseServiceImpl loginUserList = onlineUserService.list(query); - loginUserList.forEach(loginUser -> { - loginUser.setRoles(roleService.listByUserId(loginUser.getId())); - loginUser.setPermissions(roleService.listPermissionByUserId(loginUser.getId())); - LoginHelper.updateLoginUser(loginUser, loginUser.getToken()); - }); + UserContext userContext = UserContextHolder.getContext(id); + if (null != userContext) { + userContext.setRoles(roleService.listByUserId(id)); + userContext.setPermissions(roleService.listPermissionByUserId(id)); + UserContextHolder.setContext(userContext); + } } } @@ -348,7 +345,7 @@ public class UserServiceImpl extends BaseServiceImpl ids) { - CheckUtils.throwIf(CollUtil.contains(ids, LoginHelper.getUserId()), "不允许删除当前用户"); + CheckUtils.throwIf(CollUtil.contains(ids, UserContextHolder.getUserId()), "不允许删除当前用户"); List list = baseMapper.lambdaQuery() .select(UserDO::getNickname, UserDO::getIsSystem) .in(UserDO::getId, ids) diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaExtensionInterceptor.java b/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaExtensionInterceptor.java new file mode 100644 index 00000000..a7297c79 --- /dev/null +++ b/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaExtensionInterceptor.java @@ -0,0 +1,62 @@ +/* + * 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.config.satoken; + +import cn.dev33.satoken.fun.SaParamFunction; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.stp.StpUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.lang.Nullable; +import top.continew.admin.common.context.UserContextHolder; + +/** + * Sa-Token 扩展拦截器 + * + * @author Charles7c + * @since 2024/10/10 20:25 + */ +public class SaExtensionInterceptor extends SaInterceptor { + + public SaExtensionInterceptor(SaParamFunction auth) { + super(auth); + } + + @Override + public boolean preHandle(HttpServletRequest request, + HttpServletResponse response, + Object handler) throws Exception { + boolean flag = super.preHandle(request, response, handler); + if (flag && StpUtil.isLogin()) { + UserContextHolder.getContext(); + UserContextHolder.getExtraContext(); + } + return flag; + } + + @Override + public void afterCompletion(HttpServletRequest request, + HttpServletResponse response, + Object handler, + @Nullable Exception e) throws Exception { + try { + super.afterCompletion(request, response, handler, e); + } finally { + UserContextHolder.clearContext(); + } + } +} diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java b/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java index 5525c391..71ac153b 100644 --- a/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java +++ b/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java @@ -19,11 +19,12 @@ package top.continew.admin.config.satoken; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.stp.StpUtil; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContext; +import top.continew.admin.common.context.UserContextHolder; import top.continew.starter.auth.satoken.autoconfigure.SaTokenExtensionProperties; import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.util.validate.CheckUtils; @@ -54,14 +55,15 @@ public class SaTokenConfiguration { */ @Bean public SaInterceptor saInterceptor() { - return new SaInterceptor(handle -> SaRouter.match(StringConstants.PATH_PATTERN) + return new SaExtensionInterceptor(handle -> SaRouter.match(StringConstants.PATH_PATTERN) .notMatch(properties.getSecurity().getExcludes()) .check(r -> { - LoginUser loginUser = LoginHelper.getLoginUser(); + StpUtil.checkLogin(); if (SaRouter.isMatchCurrURI(loginPasswordProperties.getExcludes())) { return; } - CheckUtils.throwIf(loginUser.isPasswordExpired(), "密码已过期,请修改密码"); + UserContext userContext = UserContextHolder.getContext(); + CheckUtils.throwIf(userContext.isPasswordExpired(), "密码已过期,请修改密码"); })); } } diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenPermissionImpl.java b/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenPermissionImpl.java index 2bc6aee7..61497a73 100644 --- a/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenPermissionImpl.java +++ b/continew-admin-webapi/src/main/java/top/continew/admin/config/satoken/SaTokenPermissionImpl.java @@ -17,8 +17,8 @@ package top.continew.admin.config.satoken; import cn.dev33.satoken.stp.StpInterface; -import top.continew.admin.common.model.dto.LoginUser; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContext; +import top.continew.admin.common.context.UserContextHolder; import java.util.ArrayList; import java.util.List; @@ -33,13 +33,13 @@ public class SaTokenPermissionImpl implements StpInterface { @Override public List getPermissionList(Object loginId, String loginType) { - LoginUser loginUser = LoginHelper.getLoginUser(); - return new ArrayList<>(loginUser.getPermissions()); + UserContext userContext = UserContextHolder.getContext(); + return new ArrayList<>(userContext.getPermissions()); } @Override public List getRoleList(Object loginId, String loginType) { - LoginUser loginUser = LoginHelper.getLoginUser(); - return new ArrayList<>(loginUser.getRoleCodes()); + UserContext userContext = UserContextHolder.getContext(); + return new ArrayList<>(userContext.getRoleCodes()); } } diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java b/continew-admin-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java index 8bccd7ba..fadc59b0 100644 --- a/continew-admin-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java +++ b/continew-admin-webapi/src/main/java/top/continew/admin/controller/auth/AuthController.java @@ -35,9 +35,9 @@ 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.common.constant.CacheConstants; -import top.continew.admin.common.model.dto.LoginUser; +import top.continew.admin.common.context.UserContext; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.util.SecureUtils; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.admin.system.model.resp.UserDetailResp; import top.continew.admin.system.service.UserService; import top.continew.starter.cache.redisson.util.RedisUtils; @@ -122,12 +122,12 @@ public class AuthController { @Operation(summary = "获取用户信息", description = "获取登录用户信息") @GetMapping("/user/info") public UserInfoResp getUserInfo() { - LoginUser loginUser = LoginHelper.getLoginUser(); - UserDetailResp userDetailResp = userService.get(loginUser.getId()); + UserContext userContext = UserContextHolder.getContext(); + UserDetailResp userDetailResp = userService.get(userContext.getId()); UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class); - userInfoResp.setPermissions(loginUser.getPermissions()); - userInfoResp.setRoles(loginUser.getRoleCodes()); - userInfoResp.setPwdExpired(loginUser.isPasswordExpired()); + userInfoResp.setPermissions(userContext.getPermissions()); + userInfoResp.setRoles(userContext.getRoleCodes()); + userInfoResp.setPwdExpired(userContext.isPasswordExpired()); return userInfoResp; } @@ -135,6 +135,6 @@ public class AuthController { @Operation(summary = "获取路由信息", description = "获取登录用户的路由信息") @GetMapping("/route") public List listRoute() { - return loginService.buildRouteTree(LoginHelper.getUserId()); + return loginService.buildRouteTree(UserContextHolder.getUserId()); } } \ No newline at end of file diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/MessageController.java b/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/MessageController.java index a0ea5e75..17ccec2c 100644 --- a/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/MessageController.java +++ b/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/MessageController.java @@ -23,7 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import top.continew.admin.common.util.helper.LoginHelper; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.system.model.query.MessageQuery; import top.continew.admin.system.model.resp.MessageResp; import top.continew.admin.system.model.resp.MessageUnreadResp; @@ -53,7 +53,7 @@ public class MessageController { @Operation(summary = "分页查询列表", description = "分页查询列表") @GetMapping public PageResp page(MessageQuery query, @Validated PageQuery pageQuery) { - query.setUserId(LoginHelper.getUserId()); + query.setUserId(UserContextHolder.getUserId()); return baseService.page(query, pageQuery); } @@ -76,6 +76,6 @@ public class MessageController { @Parameter(name = "isDetail", description = "是否查询详情", example = "true", in = ParameterIn.QUERY) @GetMapping("/unread") public MessageUnreadResp countUnreadMessage(@RequestParam(required = false) Boolean detail) { - return messageUserService.countUnreadMessageByUserId(LoginHelper.getUserId(), detail); + return messageUserService.countUnreadMessageByUserId(UserContextHolder.getUserId(), detail); } } \ No newline at end of file diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/UserCenterController.java b/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/UserCenterController.java index 356c6a62..19f57a07 100644 --- a/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/UserCenterController.java +++ b/continew-admin-webapi/src/main/java/top/continew/admin/controller/system/UserCenterController.java @@ -31,8 +31,8 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import top.continew.admin.common.constant.CacheConstants; +import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.util.SecureUtils; -import top.continew.admin.common.util.helper.LoginHelper; import top.continew.admin.system.enums.SocialSourceEnum; import top.continew.admin.system.model.entity.UserSocialDO; import top.continew.admin.system.model.req.UserBasicInfoUpdateReq; @@ -73,14 +73,14 @@ public class UserCenterController { @PostMapping("/avatar") public AvatarResp updateAvatar(@NotNull(message = "头像不能为空") MultipartFile avatarFile) throws IOException { ValidationUtils.throwIf(avatarFile::isEmpty, "头像不能为空"); - String newAvatar = userService.updateAvatar(avatarFile, LoginHelper.getUserId()); + String newAvatar = userService.updateAvatar(avatarFile, UserContextHolder.getUserId()); return AvatarResp.builder().avatar(newAvatar).build(); } @Operation(summary = "修改基础信息", description = "修改用户基础信息") @PatchMapping("/basic/info") public void updateBasicInfo(@Validated @RequestBody UserBasicInfoUpdateReq req) { - userService.updateBasicInfo(req, LoginHelper.getUserId()); + userService.updateBasicInfo(req, UserContextHolder.getUserId()); } @Operation(summary = "修改密码", description = "修改用户登录密码") @@ -92,7 +92,7 @@ public class UserCenterController { String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq .getNewPassword())); ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败"); - userService.updatePassword(rawOldPassword, rawNewPassword, LoginHelper.getUserId()); + userService.updatePassword(rawOldPassword, rawNewPassword, UserContextHolder.getUserId()); } @Operation(summary = "修改手机号", description = "修改手机号") @@ -106,7 +106,7 @@ public class UserCenterController { ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误"); RedisUtils.delete(captchaKey); - userService.updatePhone(updateReq.getPhone(), rawOldPassword, LoginHelper.getUserId()); + userService.updatePhone(updateReq.getPhone(), rawOldPassword, UserContextHolder.getUserId()); } @Operation(summary = "修改邮箱", description = "修改用户邮箱") @@ -120,13 +120,13 @@ public class UserCenterController { ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED); ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误"); RedisUtils.delete(captchaKey); - userService.updateEmail(updateReq.getEmail(), rawOldPassword, LoginHelper.getUserId()); + userService.updateEmail(updateReq.getEmail(), rawOldPassword, UserContextHolder.getUserId()); } @Operation(summary = "查询绑定的三方账号", description = "查询绑定的三方账号") @GetMapping("/social") public List listSocialBind() { - List userSocialList = userSocialService.listByUserId(LoginHelper.getUserId()); + List userSocialList = userSocialService.listByUserId(UserContextHolder.getUserId()); return userSocialList.stream().map(userSocial -> { String source = userSocial.getSource(); UserSocialBindResp userSocialBind = new UserSocialBindResp(); @@ -144,13 +144,13 @@ public class UserCenterController { AuthResponse response = authRequest.login(callback); ValidationUtils.throwIf(!response.ok(), response.getMsg()); AuthUser authUser = response.getData(); - userSocialService.bind(authUser, LoginHelper.getUserId()); + userSocialService.bind(authUser, UserContextHolder.getUserId()); } @Operation(summary = "解绑三方账号", description = "解绑三方账号") @Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH) @DeleteMapping("/social/{source}") public void unbindSocial(@PathVariable String source) { - userSocialService.deleteBySourceAndUserId(source, LoginHelper.getUserId()); + userSocialService.deleteBySourceAndUserId(source, UserContextHolder.getUserId()); } }