修改为登陆后选择租户

This commit is contained in:
陈博文
2025-06-20 17:37:15 +08:00
parent a07b4c5419
commit 8f6d56a71a
12 changed files with 58 additions and 18 deletions

View File

@@ -1,7 +1,6 @@
package cn.iocoder.yudao.framework.tenant.core.web;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
@@ -14,8 +13,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
@RequiredArgsConstructor
@Slf4j
public class TenantVisitContextInterceptor implements HandlerInterceptor {
@@ -42,10 +39,10 @@ public class TenantVisitContextInterceptor implements HandlerInterceptor {
return true;
}
// 校验用户是否可切换租户
if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换租户");
}
// // 校验用户是否可切换租户
// if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
// throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换租户");
// }
// 【重点】切换租户编号
loginUser.setVisitTenantId(visitTenantId);

View File

@@ -20,6 +20,7 @@ public class LoginUser {
public static final String INFO_KEY_NICKNAME = "nickname";
public static final String INFO_KEY_DEPT_ID = "deptId";
public static final String INFO_KEY_TENANT_ID = "tenantId";
/**
* 用户编号

View File

@@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.security.core.filter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -11,8 +13,6 @@ import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
@@ -82,6 +82,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
private LoginUser buildLoginUserByToken(String token, Integer userType) {
try {
// 校验访问令牌
OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token).getCheckedData();
if (accessToken == null) {
return null;

View File

@@ -12,7 +12,7 @@ spring:
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
namespace: local # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
# 日志文件配置

View File

@@ -13,7 +13,7 @@ spring:
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
namespace: local # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
--- #################### 数据库相关配置 ####################

View File

@@ -55,4 +55,6 @@ public class TenantRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "是否可选,如果为 false 不允许在下拉选项中出现")
private Boolean optional = true;
}

View File

@@ -146,4 +146,15 @@ public class UserTenantController {
return success(userTenantService.getTenantBelongSimpleList());
}
/**
* 未关联组织机构租户 simpleList 查询接口
*/
@GetMapping("/independent-tenant-simple-list")
@Operation(summary = "获得租户 simpleList 列表")
// 不使用默认的租户查询方式,此处需要获取租户以及下属租户的相关数据,在 mapper 自行实现
@TenantIgnore
public CommonResult<List<TenantRespVO>> getIndependentTenantSimpleList() {
return success(userTenantService.getIndependentTenantSimpleList());
}
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.dal.dataobject.user;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.system.enums.common.SexEnum;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
@@ -23,7 +23,7 @@ import java.util.Set;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AdminUserDO extends BaseDO {
public class AdminUserDO extends TenantBaseDO {
/**
* 用户ID

View File

@@ -11,7 +11,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
@@ -159,13 +158,14 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
}
private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) {
Map<String, String> userInfo = buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType());
OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken())
.setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType())
.setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType()))
.setUserInfo(userInfo)
.setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes())
.setRefreshToken(refreshTokenDO.getRefreshToken())
.setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getAccessTokenValiditySeconds()));
accessTokenDO.setTenantId(TenantContextHolder.getTenantId()); // 手动设置租户编号,避免缓存到 Redis 的时候,无对应的租户编号
accessTokenDO.setTenantId(Long.parseLong(userInfo.getOrDefault(LoginUser.INFO_KEY_TENANT_ID,"0")));
oauth2AccessTokenMapper.insert(accessTokenDO);
// 记录到 Redis 中
oauth2AccessTokenRedisDAO.set(accessTokenDO);
@@ -200,7 +200,8 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
AdminUserDO user = adminUserService.getUser(userId);
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
.put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build();
.put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId()))
.put(LoginUser.INFO_KEY_TENANT_ID, user.getTenantId().toString()).build();
} else if (userType.equals(UserTypeEnum.MEMBER.getValue())) {
// 注意:目前 Member 暂时不读取,可以按需实现
return Collections.emptyMap();

View File

@@ -81,5 +81,10 @@ public interface UserTenantService {
* @return 租户列表(只含 id、name
*/
List<TenantRespVO> getTenantBelongSimpleList();
/**
* 未关联组织机构租户 simpleList 查询接口 列表
* @return 租户列表(只含 id、name
*/
List<TenantRespVO> getIndependentTenantSimpleList();
}

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
@@ -180,6 +181,27 @@ public class UserTenantServiceImpl implements UserTenantService {
return BeanUtils.toBean(tenants, TenantRespVO.class);
}
/**
* 未关联组织机构租户 simpleList 查询接口 列表
*
* @return 租户列表(只含 id、name
*/
@Override
public List<TenantRespVO> getIndependentTenantSimpleList() {
// 查询所有已关联组织的租户
List<DeptDO> bondDepts = deptMapper.selectList(DeptDO::getIsTenant, true);
Set<Long> tenantIdSet = convertSet(bondDepts,DeptDO::getTenantId);
// 查询 not in tenantIdSet 的租户信息
List<TenantDO> bondTenants = tenantMapper.selectList(new LambdaQueryWrapperX<TenantDO>().in(TenantDO::getId, tenantIdSet));
List<TenantDO> tenants = tenantMapper.selectList(new LambdaQueryWrapperX<TenantDO>().notIn(TenantDO::getId, tenantIdSet));
List<TenantRespVO> result = BeanUtils.toBean(tenants, TenantRespVO.class);
// 不可选择的下拉
List<TenantRespVO> notOptionalResult = BeanUtils.toBean(bondTenants, TenantRespVO.class);
notOptionalResult.forEach(notOptional -> notOptional.setOptional(false));
result.addAll(notOptionalResult);
return result;
}
/**
* 递归获取所有下属部门(不含自身)
*/

View File

@@ -12,7 +12,7 @@ spring:
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
namespace: local # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
--- #################### 数据库相关配置 ####################