feat(auth): 添加免登录切换租户功能
- 新增接口获取当前用户可切换的租户列表,支持手机号和邮箱聚合租户 - 实现免登录切换租户接口,需判断当前用户权限及目标租户状态 - 编写辅助方法查找可切换的用户账户 - 添加将用户信息转换为租户选项的工具方法 - 在切换成功后生成新的访问令牌并保存登录记录
This commit is contained in:
@@ -65,6 +65,7 @@ import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -1131,6 +1132,105 @@ public class MainController extends BaseController {
|
||||
return success("登录成功", new LoginResult(access_token, user));
|
||||
}
|
||||
|
||||
@Operation(summary = "获取当前登录用户可切换的租户列表(免登录切换前置)")
|
||||
@GetMapping("/auth/switchableTenants")
|
||||
public ApiResult<?> switchableTenants() {
|
||||
User current = getLoginUser();
|
||||
if (current == null) {
|
||||
return fail("未登录或登录已过期", null);
|
||||
}
|
||||
List<TenantOption> options = new ArrayList<>();
|
||||
// 按手机号聚合(仅管理员账号)
|
||||
if (StrUtil.isNotBlank(current.getPhone())) {
|
||||
LoginParam phoneParam = new LoginParam();
|
||||
phoneParam.setPhone(current.getPhone());
|
||||
List<User> byPhone = userService.getAdminsByPhone(phoneParam);
|
||||
if (byPhone != null) {
|
||||
for (User u : byPhone) {
|
||||
options.add(toTenantOption(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 按邮箱聚合(管理员账号,按租户去重)
|
||||
if (StrUtil.isNotBlank(current.getEmail())) {
|
||||
List<User> byEmail = userService.findAccountsByEmail(current.getEmail());
|
||||
if (byEmail != null) {
|
||||
for (User u : byEmail) {
|
||||
if (!Boolean.TRUE.equals(u.getIsAdmin())) {
|
||||
continue;
|
||||
}
|
||||
final Integer tId = u.getTenantId();
|
||||
if (tId != null && options.stream().noneMatch(o -> tId.equals(o.getTenantId()))) {
|
||||
options.add(toTenantOption(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return success(options);
|
||||
}
|
||||
|
||||
@Operation(summary = "免登录切换租户(需已登录,当前用户须为目标租户管理员)")
|
||||
@PostMapping("/auth/switchTenant")
|
||||
public ApiResult<LoginResult> switchTenant(@RequestBody LoginParam param, HttpServletRequest request) {
|
||||
Integer targetTenantId = param.getTenantId();
|
||||
if (targetTenantId == null) {
|
||||
return fail("请选择租户", null);
|
||||
}
|
||||
User current = getLoginUser();
|
||||
if (current == null) {
|
||||
return fail("未登录或登录已过期", null);
|
||||
}
|
||||
// 校验目标租户在可切换范围内(与 switchableTenants 一致)
|
||||
User target = findSwitchableUser(current, targetTenantId);
|
||||
if (target == null) {
|
||||
return fail("无权切换到该租户", null);
|
||||
}
|
||||
if (!target.getStatus().equals(0)) {
|
||||
return fail("该租户账号已被冻结", null);
|
||||
}
|
||||
String access_token = generateToken(target);
|
||||
loginRecordService.saveAsync(target.getUsername(), LoginRecord.TYPE_LOGIN, null, target.getTenantId(), request);
|
||||
return success("切换成功", new LoginResult(access_token, target));
|
||||
}
|
||||
|
||||
private User findSwitchableUser(User current, Integer targetTenantId) {
|
||||
List<User> candidates = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(current.getPhone())) {
|
||||
LoginParam phoneParam = new LoginParam();
|
||||
phoneParam.setPhone(current.getPhone());
|
||||
List<User> byPhone = userService.getAdminsByPhone(phoneParam);
|
||||
if (byPhone != null) {
|
||||
candidates.addAll(byPhone);
|
||||
}
|
||||
}
|
||||
if (StrUtil.isNotBlank(current.getEmail())) {
|
||||
List<User> byEmail = userService.findAccountsByEmail(current.getEmail());
|
||||
if (byEmail != null) {
|
||||
for (User u : byEmail) {
|
||||
if (Boolean.TRUE.equals(u.getIsAdmin())) {
|
||||
candidates.add(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidates.stream()
|
||||
.filter(u -> targetTenantId.equals(u.getTenantId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private TenantOption toTenantOption(User u) {
|
||||
return new TenantOption(
|
||||
u.getTenantId(),
|
||||
u.getTenantName(),
|
||||
u.getUserId(),
|
||||
u.getUsername(),
|
||||
u.getNickname(),
|
||||
null,
|
||||
u.getAvatar()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 JWT token 并存入 Redis
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user