feat(auth): 添加免登录切换租户功能
- 新增接口获取当前用户可切换的租户列表,支持手机号和邮箱聚合租户 - 实现免登录切换租户接口,需判断当前用户权限及目标租户状态 - 编写辅助方法查找可切换的用户账户 - 添加将用户信息转换为租户选项的工具方法 - 在切换成功后生成新的访问令牌并保存登录记录
This commit is contained in:
@@ -65,6 +65,7 @@ import java.net.URLEncoder;
|
|||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -1131,6 +1132,105 @@ public class MainController extends BaseController {
|
|||||||
return success("登录成功", new LoginResult(access_token, user));
|
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
|
* 生成 JWT token 并存入 Redis
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user