mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-09-09 20:57:21 +08:00
refactor: 重构获取登录用户信息方式(线程级存储)
This commit is contained in:
@@ -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()));
|
||||
|
@@ -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 的类,填充修改信息
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -31,11 +31,6 @@ public class CacheConstants {
|
||||
*/
|
||||
public static final String DELIMITER = StringConstants.COLON;
|
||||
|
||||
/**
|
||||
* 登录用户键
|
||||
*/
|
||||
public static final String LOGIN_USER_KEY = "LOGIN_USER";
|
||||
|
||||
/**
|
||||
* 验证码键前缀
|
||||
*/
|
||||
|
@@ -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;
|
@@ -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<RoleDTO> roles;
|
||||
private Set<RoleContext> 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<String> permissions, Set<RoleDTO> roles, Integer passwordExpirationDays) {
|
||||
public UserContext(Set<String> permissions, Set<RoleContext> roles, Integer passwordExpirationDays) {
|
||||
this.permissions = permissions;
|
||||
this.setRoles(roles);
|
||||
this.passwordExpirationDays = passwordExpirationDays;
|
||||
}
|
||||
|
||||
public void setRoles(Set<RoleDTO> roles) {
|
||||
public void setRoles(Set<RoleContext> roles) {
|
||||
this.roles = roles;
|
||||
this.roleCodes = roles.stream().map(RoleDTO::getCode).collect(Collectors.toSet());
|
||||
this.roleCodes = roles.stream().map(RoleContext::getCode).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
@@ -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<UserContext> CONTEXT_HOLDER = new ThreadLocal<>();
|
||||
private static final ThreadLocal<UserExtraContext> 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();
|
||||
}
|
||||
}
|
@@ -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));
|
||||
}
|
||||
}
|
@@ -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(<a href="https://gitee.com/dromara/RuoYi-Vue-Plus">RuoYi-Vue-Plus</a>)
|
||||
* @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));
|
||||
}
|
||||
}
|
@@ -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<LoginUser> list(OnlineUserQuery query);
|
||||
List<OnlineUserResp> list(OnlineUserQuery query);
|
||||
|
||||
/**
|
||||
* 查询 Token 最后活跃时间
|
||||
|
@@ -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<Set<String>> permissionFuture = CompletableFuture.supplyAsync(() -> roleService
|
||||
.listPermissionByUserId(userId), threadPoolTaskExecutor);
|
||||
CompletableFuture<Set<RoleDTO>> roleFuture = CompletableFuture.supplyAsync(() -> roleService
|
||||
CompletableFuture<Set<RoleContext>> roleFuture = CompletableFuture.supplyAsync(() -> roleService
|
||||
.listByUserId(userId), threadPoolTaskExecutor);
|
||||
CompletableFuture<Integer> 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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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<OnlineUserResp> page(OnlineUserQuery query, PageQuery pageQuery) {
|
||||
List<LoginUser> loginUserList = this.list(query);
|
||||
List<OnlineUserResp> list = BeanUtil.copyToList(loginUserList, OnlineUserResp.class);
|
||||
List<OnlineUserResp> list = this.list(query);
|
||||
return PageResp.build(pageQuery.getPage(), pageQuery.getSize(), list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LoginUser> list(OnlineUserQuery query) {
|
||||
List<LoginUser> loginUserList = new ArrayList<>();
|
||||
// 查询所有登录用户
|
||||
public List<OnlineUserResp> list(OnlineUserQuery query) {
|
||||
List<OnlineUserResp> list = new ArrayList<>();
|
||||
// 查询所有在线 Token
|
||||
List<String> tokenKeyList = StpUtil.searchTokenValue(StringConstants.EMPTY, 0, -1, false);
|
||||
tokenKeyList.parallelStream().forEach(tokenKey -> {
|
||||
Map<Long, List<String>> 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<Long, List<String>> 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<Date> 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<Date> 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<Date> 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));
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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<UserRoleDO> {
|
||||
|
||||
/**
|
||||
* 根据用户 ID 查询
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @return 角色 ID 列表
|
||||
*/
|
||||
@Select("SELECT role_id FROM sys_user_role WHERE user_id = #{userId}")
|
||||
List<Long> selectRoleIdByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
@@ -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<RoleResp, RoleDetailResp, RoleQ
|
||||
* @param userId 用户 ID
|
||||
* @return 角色集合
|
||||
*/
|
||||
Set<RoleDTO> listByUserId(Long userId);
|
||||
Set<RoleContext> listByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据角色编码查询
|
||||
|
@@ -59,6 +59,14 @@ public interface UserRoleService {
|
||||
*/
|
||||
List<Long> listRoleIdByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据角色 ID 查询
|
||||
*
|
||||
* @param roleId 角色 ID
|
||||
* @return 用户 ID 列表
|
||||
*/
|
||||
List<Long> listUserIdByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 根据角色 ID 判断是否已被用户关联
|
||||
*
|
||||
|
@@ -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<RoleMapper, RoleDO, RoleRes
|
||||
boolean isSaveDeptSuccess = roleDeptService.add(req.getDeptIds(), id);
|
||||
// 如果功能权限或数据权限有变更,则更新在线用户权限信息
|
||||
if (isSaveMenuSuccess || isSaveDeptSuccess || ObjectUtil.notEqual(req.getDataScope(), oldDataScope)) {
|
||||
OnlineUserQuery query = new OnlineUserQuery();
|
||||
query.setRoleId(id);
|
||||
List<LoginUser> 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<Long> 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<RoleMapper, RoleDO, RoleRes
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleDTO> listByUserId(Long userId) {
|
||||
public Set<RoleContext> listByUserId(Long userId) {
|
||||
List<Long> roleIdList = userRoleService.listRoleIdByUserId(userId);
|
||||
List<RoleDO> 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
|
||||
|
@@ -75,7 +75,24 @@ public class UserRoleServiceImpl implements UserRoleService {
|
||||
@Override
|
||||
@ContainerMethod(namespace = ContainerConstants.USER_ROLE_ID_LIST, type = MappingType.ORDER_OF_KEYS)
|
||||
public List<Long> 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<Long> listUserIdByRoleId(Long roleId) {
|
||||
return baseMapper.lambdaQuery()
|
||||
.select(UserRoleDO::getUserId)
|
||||
.eq(UserRoleDO::getRoleId, roleId)
|
||||
.list()
|
||||
.stream()
|
||||
.map(UserRoleDO::getUserId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -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<UserMapper, UserDO, UserRes
|
||||
String phone = req.getPhone();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, id), errorMsgTemplate, phone);
|
||||
DisEnableStatusEnum newStatus = req.getStatus();
|
||||
CheckUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(newStatus) && ObjectUtil.equal(id, LoginHelper
|
||||
CheckUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(newStatus) && ObjectUtil.equal(id, UserContextHolder
|
||||
.getUserId()), "不允许禁用当前用户");
|
||||
UserDO oldUser = super.getById(id);
|
||||
if (Boolean.TRUE.equals(oldUser.getIsSystem())) {
|
||||
@@ -333,14 +332,12 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
}
|
||||
// 如果角色有变更,则更新在线用户权限信息
|
||||
if (isSaveUserRoleSuccess) {
|
||||
OnlineUserQuery query = new OnlineUserQuery();
|
||||
query.setUserId(id);
|
||||
List<LoginUser> 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<UserMapper, UserDO, UserRes
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheInvalidate(key = "#ids", name = CacheConstants.USER_KEY_PREFIX, multi = true)
|
||||
public void delete(List<Long> ids) {
|
||||
CheckUtils.throwIf(CollUtil.contains(ids, LoginHelper.getUserId()), "不允许删除当前用户");
|
||||
CheckUtils.throwIf(CollUtil.contains(ids, UserContextHolder.getUserId()), "不允许删除当前用户");
|
||||
List<UserDO> list = baseMapper.lambdaQuery()
|
||||
.select(UserDO::getNickname, UserDO::getIsSystem)
|
||||
.in(UserDO::getId, ids)
|
||||
|
@@ -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<Object> 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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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(), "密码已过期,请修改密码");
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -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<String> 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<String> getRoleList(Object loginId, String loginType) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
return new ArrayList<>(loginUser.getRoleCodes());
|
||||
UserContext userContext = UserContextHolder.getContext();
|
||||
return new ArrayList<>(userContext.getRoleCodes());
|
||||
}
|
||||
}
|
||||
|
@@ -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<RouteResp> listRoute() {
|
||||
return loginService.buildRouteTree(LoginHelper.getUserId());
|
||||
return loginService.buildRouteTree(UserContextHolder.getUserId());
|
||||
}
|
||||
}
|
@@ -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<MessageResp> 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);
|
||||
}
|
||||
}
|
@@ -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<UserSocialBindResp> listSocialBind() {
|
||||
List<UserSocialDO> userSocialList = userSocialService.listByUserId(LoginHelper.getUserId());
|
||||
List<UserSocialDO> 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<AuthUser> 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());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user