修改为登陆后选择租户
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.yudao.framework.tenant.core.web;
|
package cn.iocoder.yudao.framework.tenant.core.web;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjUtil;
|
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.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
@@ -14,8 +13,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TenantVisitContextInterceptor implements HandlerInterceptor {
|
public class TenantVisitContextInterceptor implements HandlerInterceptor {
|
||||||
@@ -42,10 +39,10 @@ public class TenantVisitContextInterceptor implements HandlerInterceptor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验用户是否可切换租户
|
// // 校验用户是否可切换租户
|
||||||
if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
|
// if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
|
||||||
throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换租户");
|
// throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换租户");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 【重点】切换租户编号
|
// 【重点】切换租户编号
|
||||||
loginUser.setVisitTenantId(visitTenantId);
|
loginUser.setVisitTenantId(visitTenantId);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class LoginUser {
|
|||||||
|
|
||||||
public static final String INFO_KEY_NICKNAME = "nickname";
|
public static final String INFO_KEY_NICKNAME = "nickname";
|
||||||
public static final String INFO_KEY_DEPT_ID = "deptId";
|
public static final String INFO_KEY_DEPT_ID = "deptId";
|
||||||
|
public static final String INFO_KEY_TENANT_ID = "tenantId";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户编号
|
* 用户编号
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.security.core.filter;
|
|||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
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.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
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.security.core.util.SecurityFrameworkUtils;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
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.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@@ -82,6 +82,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
private LoginUser buildLoginUserByToken(String token, Integer userType) {
|
private LoginUser buildLoginUserByToken(String token, Integer userType) {
|
||||||
try {
|
try {
|
||||||
// 校验访问令牌
|
// 校验访问令牌
|
||||||
|
|
||||||
OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token).getCheckedData();
|
OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token).getCheckedData();
|
||||||
if (accessToken == null) {
|
if (accessToken == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ spring:
|
|||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: local # 命名空间。这里使用 dev 开发环境
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
# 日志文件配置
|
# 日志文件配置
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ spring:
|
|||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: local # 命名空间。这里使用 dev 开发环境
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
--- #################### 数据库相关配置 ####################
|
--- #################### 数据库相关配置 ####################
|
||||||
|
|||||||
@@ -55,4 +55,6 @@ public class TenantRespVO {
|
|||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "是否可选,如果为 false 不允许在下拉选项中出现")
|
||||||
|
private Boolean optional = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,4 +146,15 @@ public class UserTenantController {
|
|||||||
return success(userTenantService.getTenantBelongSimpleList());
|
return success(userTenantService.getTenantBelongSimpleList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未关联组织机构租户 simpleList 查询接口
|
||||||
|
*/
|
||||||
|
@GetMapping("/independent-tenant-simple-list")
|
||||||
|
@Operation(summary = "获得租户 simpleList 列表")
|
||||||
|
// 不使用默认的租户查询方式,此处需要获取租户以及下属租户的相关数据,在 mapper 自行实现
|
||||||
|
@TenantIgnore
|
||||||
|
public CommonResult<List<TenantRespVO>> getIndependentTenantSimpleList() {
|
||||||
|
return success(userTenantService.getIndependentTenantSimpleList());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.system.dal.dataobject.user;
|
package cn.iocoder.yudao.module.system.dal.dataobject.user;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
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 cn.iocoder.yudao.module.system.enums.common.SexEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
@@ -23,7 +23,7 @@ import java.util.Set;
|
|||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class AdminUserDO extends BaseDO {
|
public class AdminUserDO extends TenantBaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户ID
|
* 用户ID
|
||||||
|
|||||||
@@ -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.date.DateUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
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.framework.tenant.core.util.TenantUtils;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
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) {
|
private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) {
|
||||||
|
Map<String, String> userInfo = buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType());
|
||||||
OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken())
|
OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken())
|
||||||
.setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType())
|
.setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType())
|
||||||
.setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType()))
|
.setUserInfo(userInfo)
|
||||||
.setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes())
|
.setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes())
|
||||||
.setRefreshToken(refreshTokenDO.getRefreshToken())
|
.setRefreshToken(refreshTokenDO.getRefreshToken())
|
||||||
.setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getAccessTokenValiditySeconds()));
|
.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);
|
oauth2AccessTokenMapper.insert(accessTokenDO);
|
||||||
// 记录到 Redis 中
|
// 记录到 Redis 中
|
||||||
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
||||||
@@ -200,7 +200,8 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
|||||||
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
|
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
|
||||||
AdminUserDO user = adminUserService.getUser(userId);
|
AdminUserDO user = adminUserService.getUser(userId);
|
||||||
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
|
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())) {
|
} else if (userType.equals(UserTypeEnum.MEMBER.getValue())) {
|
||||||
// 注意:目前 Member 暂时不读取,可以按需实现
|
// 注意:目前 Member 暂时不读取,可以按需实现
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
|
|||||||
@@ -81,5 +81,10 @@ public interface UserTenantService {
|
|||||||
* @return 租户列表(只含 id、name)
|
* @return 租户列表(只含 id、name)
|
||||||
*/
|
*/
|
||||||
List<TenantRespVO> getTenantBelongSimpleList();
|
List<TenantRespVO> getTenantBelongSimpleList();
|
||||||
|
/**
|
||||||
|
* 未关联组织机构租户 simpleList 查询接口 列表
|
||||||
|
* @return 租户列表(只含 id、name)
|
||||||
|
*/
|
||||||
|
List<TenantRespVO> getIndependentTenantSimpleList();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
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.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO;
|
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归获取所有下属部门(不含自身)
|
* 递归获取所有下属部门(不含自身)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ spring:
|
|||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: local # 命名空间。这里使用 dev 开发环境
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
--- #################### 数据库相关配置 ####################
|
--- #################### 数据库相关配置 ####################
|
||||||
|
|||||||
Reference in New Issue
Block a user