✨ 新增管理员代登录功能

This commit is contained in:
caojia
2026-11-04 15:20:05 +08:00
parent 93da04fe5e
commit 5cccbf510f
17 changed files with 540 additions and 18 deletions
@@ -0,0 +1,80 @@
package com.bms.web.controller.system;
import com.bms.common.annotation.Log;
import com.bms.common.constant.Constants;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.domain.entity.SysUser;
import com.bms.common.core.domain.model.LoginUser;
import com.bms.common.enums.BusinessType;
import com.bms.common.enums.UserStatus;
import com.bms.common.exception.ServiceException;
import com.bms.common.utils.SecurityUtils;
import com.bms.framework.web.service.TokenService;
import com.bms.framework.web.service.UserDetailsServiceImpl;
import com.bms.system.service.ISysUserService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** 管理员以目标用户身份排查问题。 */
@RestController
@RequestMapping("/system/user/impersonation")
public class SysImpersonationController {
private static final long MAX_DURATION_MILLIS = 30 * 60 * 1000L;
private final ISysUserService userService;
private final UserDetailsServiceImpl userDetailsService;
private final TokenService tokenService;
public SysImpersonationController(ISysUserService userService, UserDetailsServiceImpl userDetailsService,
TokenService tokenService) {
this.userService = userService;
this.userDetailsService = userDetailsService;
this.tokenService = tokenService;
}
@PreAuthorize("@ss.hasPermi('system:user:impersonate')")
@Log(title = "用户代登录", businessType = BusinessType.GRANT, isSaveResponseData = false)
@PostMapping("/{userId}")
public AjaxResult start(@PathVariable Long userId) {
LoginUser operator = SecurityUtils.getLoginUser();
// 项目中超级管理员是 user_id=1;代登录不能嵌套,也不能用于进入管理员账号。
if (!SecurityUtils.isAdmin() || operator.isImpersonating()) {
throw new ServiceException("仅超级管理员可以代登录");
}
if (userId == null || SecurityUtils.isAdmin(userId) || userId.equals(operator.getUserId())) {
throw new ServiceException("不能代登录管理员账号或当前账号");
}
userService.checkUserDataScope(userId);
SysUser target = userService.selectUserById(userId);
if (target == null || !UserStatus.OK.getCode().equals(target.getDelFlag())
|| !UserStatus.OK.getCode().equals(target.getStatus())) {
throw new ServiceException("目标用户不存在、已删除或已停用");
}
if (target.getRoles() != null && target.getRoles().stream().anyMatch(role -> role != null
&& (role.isAdmin() || Constants.SUPER_ADMIN.equals(role.getRoleKey())))) {
throw new ServiceException("不能代登录管理员角色账号");
}
LoginUser actingUser = (LoginUser) userDetailsService.createLoginUser(target);
actingUser.setImpersonatorId(operator.getUserId());
actingUser.setImpersonatorName(operator.getUsername());
actingUser.setImpersonatorToken(operator.getToken());
actingUser.setImpersonationExpireTime(System.currentTimeMillis() + MAX_DURATION_MILLIS);
AjaxResult result = AjaxResult.success();
result.put(Constants.TOKEN, tokenService.createToken(actingUser));
return result;
}
@Log(title = "退出用户代登录", businessType = BusinessType.OTHER, isSaveResponseData = false)
@PostMapping("/exit")
public AjaxResult exit() {
LoginUser user = SecurityUtils.getLoginUser();
if (!user.isImpersonating()) {
throw new ServiceException("当前不是代登录会话");
}
tokenService.delLoginUser(user.getToken());
return AjaxResult.success();
}
}
@@ -87,6 +87,7 @@ public class SysLoginController
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
ajax.put("impersonating", loginUser.isImpersonating());
ajax.put("pwdChrtype", getSysAccountChrtype());
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));