新增组织产品有效性的检查能力

This commit is contained in:
gaoqr
2025-09-24 09:36:24 +08:00
parent 6e365e77aa
commit c070584159
22 changed files with 174 additions and 15 deletions
@@ -25,6 +25,7 @@ public class GlobalErrorCodeConstants {
public static final ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确"); public static final ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
public static final ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许 public static final ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
public static final ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试"); public static final ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
public static final ErrorCode ORG_PRODUCT_EXPIRED = new ErrorCode(410, "组织产品套餐已过期,请续费后继续使用");
// ========== 服务端错误段 ========== // ========== 服务端错误段 ==========
@@ -32,6 +32,11 @@ public class OrganProperties {
*/ */
private Set<String> ignoreUrls = Collections.emptySet(); private Set<String> ignoreUrls = Collections.emptySet();
/**
* 需要忽略产品检查的请求
*/
private Set<String> ignoreProductUrls = Collections.emptySet();
/** /**
* 需要忽略多组织的表 * 需要忽略多组织的表
* *
@@ -2,6 +2,7 @@ package com.cf.imes.framework.organ.core.security;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.enums.UserTypeEnum;
import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.pojo.CommonResult;
@@ -23,6 +24,7 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
@@ -31,7 +33,7 @@ import java.util.Objects;
* 1. 如果是登陆的用户,校验是否有权限访问该组织,避免越权问题。 * 1. 如果是登陆的用户,校验是否有权限访问该组织,避免越权问题。
* 2. 如果请求未带组织的编号,检查是否是忽略的 URL,否则也不允许访问。 * 2. 如果请求未带组织的编号,检查是否是忽略的 URL,否则也不允许访问。
* 3. 校验组织是合法,例如说被禁用、到期 * 3. 校验组织是合法,例如说被禁用、到期
* * <p>
* 校验用户访问的组织,是否是其所在的组织, * 校验用户访问的组织,是否是其所在的组织,
* *
* @author 晨丰科技 * @author 晨丰科技
@@ -70,7 +72,7 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
if (organId == null) { if (organId == null) {
organId = user.getOrganId(); organId = user.getOrganId();
OrganContextHolder.setOrganId(organId); OrganContextHolder.setOrganId(organId);
// 如果传递了组织编号,则进行比对组织编号,避免越权问题 // 如果传递了组织编号,则进行比对组织编号,避免越权问题
} else if (!Objects.equals(user.getOrganId(), OrganContextHolder.getOrganId())) { // Cloud 特殊逻辑:如果是 RPC 请求,就不校验了。主要考虑,一些场景下,会调用 OrganUtils 去切换组织 } else if (!Objects.equals(user.getOrganId(), OrganContextHolder.getOrganId())) { // Cloud 特殊逻辑:如果是 RPC 请求,就不校验了。主要考虑,一些场景下,会调用 OrganUtils 去切换组织
log.error("[doFilterInternal][组织({}) User({}/{}) 越权访问组织({}) URL({}/{})]", log.error("[doFilterInternal][组织({}) User({}/{}) 越权访问组织({}) URL({}/{})]",
user.getOrganId(), user.getId(), user.getUserType(), user.getOrganId(), user.getId(), user.getUserType(),
@@ -98,6 +100,10 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
// 校验部门 // 校验部门
organFrameworkService.validDept(deptId); organFrameworkService.validDept(deptId);
} }
// 校验组织产品有效性
validOrgnProduct(user, request);
} catch (Throwable ex) { } catch (Throwable ex) {
CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex); CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex);
// 组织失效返回401踢出系统 // 组织失效返回401踢出系统
@@ -115,6 +121,19 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
chain.doFilter(request, response); chain.doFilter(request, response);
} }
/**
* 校验组织产品有效性
*
* @param user
* @param request
*/
private void validOrgnProduct(LoginUser user, HttpServletRequest request) {
// 非管理端校验产品的有效性
if (!Objects.equals(user.getUserType(), UserTypeEnum.ADMIN.getValue()) && !isProductIgnoreUrl(request)) {
organFrameworkService.validOrgProduct(user.getOrganId(), user.getProductId());
}
}
private boolean isIgnoreUrl(HttpServletRequest request) { private boolean isIgnoreUrl(HttpServletRequest request) {
// 快速匹配,保证性能 // 快速匹配,保证性能
if (CollUtil.contains(organProperties.getIgnoreUrls(), request.getRequestURI())) { if (CollUtil.contains(organProperties.getIgnoreUrls(), request.getRequestURI())) {
@@ -129,6 +148,20 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
return false; return false;
} }
private boolean isProductIgnoreUrl(HttpServletRequest request) {
// 快速匹配,保证性能
if (CollUtil.contains(organProperties.getIgnoreProductUrls(), request.getRequestURI())) {
return true;
}
// 逐个 Ant 路径匹配
for (String url : organProperties.getIgnoreProductUrls()) {
if (pathMatcher.match(url, request.getRequestURI())) {
return true;
}
}
return false;
}
/** /**
* 是否组织失效设置未登录回调 * 是否组织失效设置未登录回调
* *
@@ -29,4 +29,12 @@ public interface OrganFrameworkService {
* @param id * @param id
*/ */
void validDept(Long id); void validDept(Long id);
/**
* 校验组织产品是否有效
*
* @param organId
* @param productId
*/
void validOrgProduct(Long organId, Long productId);
} }
@@ -1,5 +1,6 @@
package com.cf.imes.framework.organ.core.service; package com.cf.imes.framework.organ.core.service;
import cn.hutool.core.lang.Pair;
import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.cache.CacheUtils; import com.cf.imes.framework.common.util.cache.CacheUtils;
import com.cf.imes.module.system.api.dept.DeptApi; import com.cf.imes.module.system.api.dept.DeptApi;
@@ -66,6 +67,20 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
}); });
/**
* 针对 {@link #validOrgProduct(Long, Long)} 的缓存
*/
private final LoadingCache<Pair<Long, Long>, CommonResult<Boolean>> validOrgProduct = CacheUtils.buildCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<>() {
@Override
public CommonResult<Boolean> load(Pair<Long, Long> pair) {
return organApi.validOrganProduct(pair.getKey(), pair.getValue());
}
});
@Override @Override
@SneakyThrows @SneakyThrows
public List<Long> getOrganIds() { public List<Long> getOrganIds() {
@@ -83,4 +98,10 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
public void validDept(Long id) { public void validDept(Long id) {
validOrganDept.get(id).checkError(); validOrganDept.get(id).checkError();
} }
@Override
@SneakyThrows
public void validOrgProduct(Long organId, Long productId) {
validOrgProduct.get(new Pair<>(organId, productId)).checkError();
}
} }
@@ -85,4 +85,9 @@ public class LoginUser {
* 用户昵称 * 用户昵称
*/ */
private String nickname; private String nickname;
/**
* 产品id
*/
private Long productId;
} }
@@ -101,7 +101,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
// 构建登录用户 // 构建登录用户
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
.setOrganId(accessToken.getOrganId()).setScopes(accessToken.getScopes()).setIsSupAdmin(accessToken.getIsSupAdmin()) .setOrganId(accessToken.getOrganId()).setScopes(accessToken.getScopes()).setIsSupAdmin(accessToken.getIsSupAdmin())
.setLarge(accessToken.getLarge()).setDbNo(accessToken.getDbNo()).setTableNo(accessToken.getTableNo()); .setLarge(accessToken.getLarge()).setDbNo(accessToken.getDbNo()).setTableNo(accessToken.getTableNo())
.setProductId(accessToken.getProductId());
} catch (ServiceException serviceException) { } catch (ServiceException serviceException) {
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可 // 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
return null; return null;
@@ -178,4 +178,17 @@ public class SecurityFrameworkUtils {
Long organId = (organIds != null && organIds.length > 0) ? organIds[0] : getUserOrganId(); Long organId = (organIds != null && organIds.length > 0) ? organIds[0] : getUserOrganId();
return Objects.equals(organId, CF_ORGANID); return Objects.equals(organId, CF_ORGANID);
} }
/**
* 获取当前登录用户的productId
*
* @return
*/
public static Long getProductId() {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED);
}
return loginUser.getProductId();
}
} }
@@ -69,4 +69,10 @@ public class LoginUser {
* 灰度默认版本号 * 灰度默认版本号
*/ */
private String grayDefaultVersion; private String grayDefaultVersion;
/**
* 产品id
*/
private Long productId;
} }
@@ -151,7 +151,8 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered {
.setLarge(tokenInfo.getLarge()).setDbNo(tokenInfo.getDbNo()).setTableNo(tokenInfo.getTableNo()) .setLarge(tokenInfo.getLarge()).setDbNo(tokenInfo.getDbNo()).setTableNo(tokenInfo.getTableNo())
.setDataCode(tokenInfo.getDataCode()).setIsSupAdmin(tokenInfo.getIsSupAdmin()) .setDataCode(tokenInfo.getDataCode()).setIsSupAdmin(tokenInfo.getIsSupAdmin())
.setNickname(tokenInfo.getNickname()).setDeptId(tokenInfo.getDeptId()) .setNickname(tokenInfo.getNickname()).setDeptId(tokenInfo.getDeptId())
.setGrayVersion(tokenInfo.getGrayVersion()).setGrayDefaultVersion(tokenInfo.getGrayDefaultVersion()); .setGrayVersion(tokenInfo.getGrayVersion()).setGrayDefaultVersion(tokenInfo.getGrayDefaultVersion())
.setProductId(tokenInfo.getProductId());
} }
@Override @Override
@@ -43,4 +43,7 @@ public class OAuth2AccessTokenCheckRespDTO implements Serializable {
@Schema(description = "灰度默认版本号", example = "1") @Schema(description = "灰度默认版本号", example = "1")
private String grayDefaultVersion; private String grayDefaultVersion;
@Schema(description = "产品id", example = "1")
private Long productId;
} }
@@ -53,5 +53,9 @@ public interface OrganApi {
@Operation(summary = "根据组织名称获取组织的信息") @Operation(summary = "根据组织名称获取组织的信息")
CommonResult<List<OrganizationDTO>> getOrganDetailsByName(@RequestParam("organName") String organName); CommonResult<List<OrganizationDTO>> getOrganDetailsByName(@RequestParam("organName") String organName);
@GetMapping(PREFIX + "/valid/product")
@Operation(summary = "校验组织产品是否有效")
@Parameter(name = "organId", description = "组织编号", required = true, example = "1024")
@Parameter(name = "productId", description = "产品编号", required = true, example = "1024")
CommonResult<Boolean> validOrganProduct(@RequestParam("organId") Long organId, @RequestParam("id") Long productId);
} }
@@ -8,7 +8,8 @@ import com.cf.imes.module.system.api.organ.dto.OrgStatisticsIsLapseRespDTO;
import com.cf.imes.module.system.api.organ.dto.OrgStatisticsReqDTO; import com.cf.imes.module.system.api.organ.dto.OrgStatisticsReqDTO;
import com.cf.imes.module.system.api.organ.dto.OrganizationDTO; import com.cf.imes.module.system.api.organ.dto.OrganizationDTO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganRespVO; import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganRespVO;
import com.cf.imes.module.system.dal.mysql.organ.OrganMapper; import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.service.organ.OrganService; import com.cf.imes.module.system.service.organ.OrganService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -19,6 +20,8 @@ import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants.ORG_PRODUCT_EXPIRED;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.framework.common.pojo.CommonResult.success; import static com.cf.imes.framework.common.pojo.CommonResult.success;
import static com.cf.imes.framework.common.util.time.StatisticsChangeUtils.generateDateRangeAxis; import static com.cf.imes.framework.common.util.time.StatisticsChangeUtils.generateDateRangeAxis;
import static com.cf.imes.framework.common.util.time.StatisticsChangeUtils.getDateList; import static com.cf.imes.framework.common.util.time.StatisticsChangeUtils.getDateList;
@@ -30,9 +33,8 @@ public class OrganApiImpl implements OrganApi {
@Resource @Resource
private OrganService organService; private OrganService organService;
@Resource @Resource
private OrganMapper organMapper; private PurchaseService purchaseService;
@Override @Override
@@ -139,4 +141,15 @@ public class OrganApiImpl implements OrganApi {
LocalDate[] time = reqVO.getCreateTime(); LocalDate[] time = reqVO.getCreateTime();
reqVO.setCreateTime(new LocalDate[]{time[0], time[1]}); reqVO.setCreateTime(new LocalDate[]{time[0], time[1]});
} }
@Override
public CommonResult<Boolean> validOrganProduct(Long organId, Long productId) {
List<PurchaseRecordDO> purchaseList = purchaseService.getOrgProductPurchaseList(organId, productId);
// 如果购买记录存在大于等于当前时间的记录,则是有效期内
boolean anyMatch = purchaseList.stream().anyMatch(p -> p.getEndTime().isAfter(LocalDate.now()) || p.getEndTime().isEqual(LocalDate.now()));
if (!anyMatch) {
throw exception(ORG_PRODUCT_EXPIRED);
}
return success(anyMatch);
}
} }
@@ -54,6 +54,5 @@ public class TenantPackageDO extends BaseDO {
/** /**
* 产品id * 产品id
*/ */
@TableField(exist = false)
private Long productId; private Long productId;
} }
@@ -161,9 +161,12 @@ public class AdminAuthServiceImpl implements AdminAuthService {
// 使用账号密码,进行登录 // 使用账号密码,进行登录
AdminUserDO user = authenticate(reqVO); AdminUserDO user = authenticate(reqVO);
Long userId = user.getId();
// 非管理端设置产品id到token
user.setProductId(!isManageEndPoint ? productProperties.getImesProduct() : null);
// 管理端只允许超管登录 // 管理端只允许超管登录
Long userId = user.getId();
boolean isSuperAdmin = securityFrameworkService.hasAnyRoles(userId, "super_admin"); boolean isSuperAdmin = securityFrameworkService.hasAnyRoles(userId, "super_admin");
user.setSuperAdmin(isSuperAdmin); user.setSuperAdmin(isSuperAdmin);
if (isSuperAdmin || SecurityFrameworkUtils.isCfOrg(user.getOrganId())) { if (isSuperAdmin || SecurityFrameworkUtils.isCfOrg(user.getOrganId())) {
@@ -116,6 +116,15 @@ public interface PurchaseService {
*/ */
PurchaseRecordDO getOrgInitialPurchaseRecord(Long organId, Long productId); PurchaseRecordDO getOrgInitialPurchaseRecord(Long organId, Long productId);
/**
* 获取组织产品购买记录
*
* @param organId
* @param productId
* @return
*/
List<PurchaseRecordDO> getOrgProductPurchaseList(Long organId, Long productId);
/** /**
* 获取组织续费定价规则列表 * 获取组织续费定价规则列表
* *
@@ -235,6 +235,15 @@ public class PurchaseServiceImpl implements PurchaseService {
.eq(PurchaseRecordDO::getInitial, true)); .eq(PurchaseRecordDO::getInitial, true));
} }
@Override
public List<PurchaseRecordDO> getOrgProductPurchaseList(Long organId, Long productId) {
return purchaseRecordMapper.selectList(new LambdaQueryWrapper<PurchaseRecordDO>()
.eq(PurchaseRecordDO::getOrganId, organId)
.eq(PurchaseRecordDO::getProductId, productId)
.eq(PurchaseRecordDO::getDeleted, false)
.ne(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.PENDING.getStatus()));
}
@Override @Override
public List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId) { public List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId) {
// 校验产品 // 校验产品
@@ -6,6 +6,7 @@ import com.cf.imes.module.system.controller.admin.organ.vo.packages.TenantPackag
import com.cf.imes.module.system.dal.dataobject.organ.TenantPackageDO; import com.cf.imes.module.system.dal.dataobject.organ.TenantPackageDO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -80,4 +81,12 @@ public interface TenantPackageService {
* @return * @return
*/ */
Set<Long> getTenantPackageMenuIds(Long id); Set<Long> getTenantPackageMenuIds(Long id);
/**
* 获取产品套餐下的权限菜单id
*
* @param productId 产品id
* @return
*/
Set<Long> getProductTenantPackageMenuIds(Long productId);
} }
@@ -166,4 +166,15 @@ public class TenantPackageServiceImpl implements TenantPackageService {
return null; return null;
} }
} }
@Override
@Cacheable(value = RedisKeyConstants.TENANT_PACKAGE_MENU_IDS, key = "#productId", unless = "#result == null or #result.isEmpty()", cacheManager = "redisCacheManager")
public Set<Long> getProductTenantPackageMenuIds(Long productId) {
TenantPackageDO tenantPackageDO = tenantPackageMapper.selectOne(new LambdaQueryWrapper<TenantPackageDO>().eq(TenantPackageDO::getProductId, productId).select(TenantPackageDO::getMenuIds));
if (ObjectUtil.isNotNull(tenantPackageDO)) {
return tenantPackageDO.getMenuIds();
} else {
return Set.of();
}
}
} }
@@ -388,7 +388,7 @@ public class PermissionServiceImpl implements PermissionService {
if (roleService.hasAnySuperAdmin(roleIds)) { if (roleService.hasAnySuperAdmin(roleIds)) {
return convertSet(menuService.getMenuList(), MenuDO::getId); return convertSet(menuService.getMenuList(), MenuDO::getId);
} else { } else {
List<Long> buildinRoleIdList = new ArrayList<>(){{ List<Long> buildinRoleIdList = new ArrayList<>() {{
add(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID); add(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID);
add(InternalRoleConstants.ORGAN_STAFF_ROLE_ID); add(InternalRoleConstants.ORGAN_STAFF_ROLE_ID);
}}; }};
@@ -402,10 +402,7 @@ public class PermissionServiceImpl implements PermissionService {
roleMenuIds = convertSet(roleMenuMapper.selectListByRoleIdsAndOrganId(roleIds, OrganContextHolder.getOrganId()), RoleMenuDO::getMenuId); roleMenuIds = convertSet(roleMenuMapper.selectListByRoleIdsAndOrganId(roleIds, OrganContextHolder.getOrganId()), RoleMenuDO::getMenuId);
} }
// 校验、获取可用的组织 Set<Long> tenantPackageMenuIds = tenantPackageService.getProductTenantPackageMenuIds(SecurityFrameworkUtils.getProductId());
OrganizationDO organ = organService.validOrgan(organId);
Set<Long> tenantPackageMenuIds = tenantPackageService.getTenantPackageMenuIds(organ.getPackageId());
return Sets.intersection(roleMenuIds, tenantPackageMenuIds); return Sets.intersection(roleMenuIds, tenantPackageMenuIds);
} }
@@ -196,6 +196,9 @@ chenfeng:
#- /rpc-api/system/error-code/* # 错误码的自动创建与下载的接口,无法带上组织编号 #- /rpc-api/system/error-code/* # 错误码的自动创建与下载的接口,无法带上组织编号
#- /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递组织编号;主要解决上传文件的场景,前端不会传递 tenant-id! #- /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递组织编号;主要解决上传文件的场景,前端不会传递 tenant-id!
#- /rpc-api/system/permission/has-any-permissions #- /rpc-api/system/permission/has-any-permissions
ignore-product-urls:
- /admin-api/system/auth/get-permission-info
- /admin-api/system/dict-data/list-all-simple
ignore-tables: ignore-tables:
- system_organization - system_organization
- system_tenant_package - system_tenant_package
@@ -278,6 +281,8 @@ chenfeng:
publicKeyString: F+bPjhy/AwNvl16dMdqHCgKYIfA9c8Tho+g+fAeNOb7GjQf0NCX36B2ZH7yngpN6v82Q10/PfblVrPGrvMbDZcU4gxomhXN22L2hfaijPESgodEuoAd89Z31WYFuRRCKxAWWzjhXa+E5bBSUpMkuToLlgZgqiLmAmjfTJO9NOIM0i0+D/2foka4ALixhyklznefk8Dz2RwFb60luZSUE03NFoqp1/uifn6LB4r/Lery1wH8b1EN5rgjvJXDIRGsyaHWbtdQr0sB0NW6LoR5PzZPeq4X4DE6iBDzG7u55kFCFwVQXmxCgHN4bdniVHcu28m9piCTuvyGQHXZ2J6prsytv/N24ef/xBVTHMMx+bcj+AIB0z44/OfgK4DF2U4JURNsCmD9h6dY60Hi6kFHOe8Y9GcR8T9V2LrfOJdm2mX19U+ziCE7jo0zllxo6vzLCMwjfm61gWhxU30fOaZgXbhGHps3z/TS5LlYiLgZcv3LE+Ttvl3fl0Cm3SitvNqxwQTnLxxKjcr2+ZE523Azr6/6JF1t8wSBKz4MAH9FrNvHVbziu7QrrWOFpCUL22sbBXtglQvQ1fjHqQ84qcGh6fDJC9k3f+lWVX1jAQiJT6h2MjfwaSIbhUGFS1BG6mQ== publicKeyString: F+bPjhy/AwNvl16dMdqHCgKYIfA9c8Tho+g+fAeNOb7GjQf0NCX36B2ZH7yngpN6v82Q10/PfblVrPGrvMbDZcU4gxomhXN22L2hfaijPESgodEuoAd89Z31WYFuRRCKxAWWzjhXa+E5bBSUpMkuToLlgZgqiLmAmjfTJO9NOIM0i0+D/2foka4ALixhyklznefk8Dz2RwFb60luZSUE03NFoqp1/uifn6LB4r/Lery1wH8b1EN5rgjvJXDIRGsyaHWbtdQr0sB0NW6LoR5PzZPeq4X4DE6iBDzG7u55kFCFwVQXmxCgHN4bdniVHcu28m9piCTuvyGQHXZ2J6prsytv/N24ef/xBVTHMMx+bcj+AIB0z44/OfgK4DF2U4JURNsCmD9h6dY60Hi6kFHOe8Y9GcR8T9V2LrfOJdm2mX19U+ziCE7jo0zllxo6vzLCMwjfm61gWhxU30fOaZgXbhGHps3z/TS5LlYiLgZcv3LE+Ttvl3fl0Cm3SitvNqxwQTnLxxKjcr2+ZE523Azr6/6JF1t8wSBKz4MAH9FrNvHVbziu7QrrWOFpCUL22sbBXtglQvQ1fjHqQ84qcGh6fDJC9k3f+lWVX1jAQiJT6h2MjfwaSIbhUGFS1BG6mQ==
privateKeyString: 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 privateKeyString: P+7gYGAyY0lKxrzAowku4RCubro0QjTPX6IHP8oOmsgLnhzkF9EiWvyrcWrzHOsu6/JPrMM0NW7bC/2DSTmvGw9m2p8AI8syLT/1neQXJNq6N9TgbGVNfsYYsc2EKTmJhl1Y1ZuOEgze24n3HUmUwHCFUCc9LQQ5wHFhhVPwbyMEd7hHXnolEZ2qIBonCwX0bBX2NUHdHUDRHFBHbxDeypeA9G/Z9Wz1hkyRXAlPUdhnVhEVXb9/3ynvfLdCk4kTpZYR3D31y8d8jW+3PSGeWWZRkToEhCI2xbJto//8Lt13B9nPo3r5GZTj0M44nRsjEmDsbBXOC2Y1Nu0Bnx/C7JePcnEtOiLI1P4mf7e8vhXjzY4q6NZQ7D1NXF8U4x86izvy7dD/aaN0SCDnUaT91Xi3+h+eGMitWSrAHt634xkj81ijg56H+Q0hiUby0ejgwlgyGrO2Y1yh5umYvljPyKnUNagZJFmsG85yJ2CX4a5McGHitAAJhJzqwq2+bTIESd61TZCqIVDLV42AZMrEq25DXjgFwoBD5tnbh8EMIGhAWIXMTbEKQy5NV5bWbY/w4XUSl16v6K6W3RtgK8UANAoipIOcaReQ/25lxRN2C6tbPoRnG4ddHUj2J5/fG9X3FfJ1BVBqopCtzp/vnntq+73DgQy3dthB7EA1cCgHzlPGdTTe6O6N7gMwjA2SdtFTQtxEX6Pi8JhjuEF5zSsMvs1CWxh3l/mRFCwQw3qrEU/q1CFeIWQF2o3swhXPjcNWz38zPdFTvADsXz+GowN2IsQdq/uvRHFqBSyEMBcEGyn5VqRcmcB5Rk0L6dD3lKGOn/9H+3z+s2Ljf9dXdXm9jv/Nld20klrQs0ySwmIcbWra7vD4iUwNEx+F/QoeDsAI3OhUGaaoir+dJ6pjwFZO/A3P20dseZLRVlvGCE6cFVfJenv4pBTpOmKTFiLKsqyk3MykaDwRwSvCLI0NHKDI+ckgiTHTVoL+0gjjVtKlyFJk0whY6lu7lObNKj+DbDmetWMa1EWhzcscVX1f6dzTRRo9GjL+SFQT4s1dGjQ9lOpmP1ICP6X5C9MuJ/y2ScZ7ywSkrqmnxAPi122T8hVDRL/HwqxneKP3oWl1DlDHcQoAQqo8iwRDs9e2gta48g4J/NyX2FJ76I2F86L//qhuKq0uSXQTr6ara4eKeFi8fjdbipEOsvP6wEQEFegH//7o/Fta7wxj3Lt81fEqJ9XOuCW+1x6xtXowlhjNM+qF1cGNa5Jd5ATfTd3KH0ClgNk8pki8q26jRpyOChCCoZg5a1CqyzbFFaXYYNmtuuwUSgbOUIDLFtmJgpoj95oDyBzYbzPzTV26jvJIBpiM6BWFKGBcDXUPPUTGCCZo/QDIDeBBF1Ar52i5QDWUWYEwKBQ70llN4AByy+tPtqhoLNfDiNvEDMxXEOh+beB3U5wUKMm4f3TP2VpGjgYBMCNwoV4v/iNhDrdvzmhmRYUDCTF1ttn2LlFKAO+Yba7IPwAjHMGHZ7pm6/bJ/bAAi57Kr7C5sO38Ovi7ilkn2yXC4ZOCZe0En7n3AUyGwvcDB7RkW08U6mVMKHr8mKT8wpt0ia1IJDmuHMO7r6dJWMimIBeY+eo8R3/NZY7hLyLd0mz+onq+nYYSJBzXG1J0I9VYcU7T7/RMk+pt6W1Jb3jkd+oytK0LANumN4Tb4ufnJevYyq3wRiQV5V7aZNyvPWLQigdc2Q3MkmZ8PCTcRDnhVw8h7WxgvwiArKe2ThF7UdFEa8cnyp7ATu77fw1DlIyzLFscOiOleBp67+e+kEzXNoQkGKsBxkBZrfK03fw5+8SMB/59c7UB6Ym92BO9U8CyrwyoDq9Im75wPDXR3KedjBLvbpEOBQsf2v0a3CUfIdpCP4r9R2SGKK3PAsl1/I+/5/ICF+7wHpmZMg4DO5CqpKGnHop4qkg/JXbTpeKeCrZpMZXVJxsr/4a4wHGWl+LqbUFhwfUS+9dRGXnx047g+lDLBp2evHE2w11wlLJeDW/5tmxDAzqb3fI9ZMAFfhkj8jkAL6HtNMg3iDevp9F42pgHkrdkXcChTsQWfKNMqKjRkfscgmVvtcnPHTbke8F8UlKqRAWaTKpir9xpbhvD53eNDktjC5cwKG/k7vj3etojBzhGO3txtHlTzSMBO/Mjf7guTNVyb5f+DTSjYhjLvYVKBtH1dlXlFW/V1xefyVxrKynPaNzid4kPWLd7j8d3JbMv+/JlZRxTT2CUskLtrBH1xg7RNRx6sKtmBd+wE7jMwhCvzIa00OBqKwJZk1jcqWtcwKPm7y14eg==
notifyUrl: RIEeHCoPHaAryuVN6mEYskBSl+EPvhsxRpjIbuIE7f7jABVxm46bLc01WQUe4Fn9NPYyNTv0xCxM68iRrmFDjAUjQ/hkIVNG+yD/kNsjcYCWa2gtOQPrvWZzDA== notifyUrl: RIEeHCoPHaAryuVN6mEYskBSl+EPvhsxRpjIbuIE7f7jABVxm46bLc01WQUe4Fn9NPYyNTv0xCxM68iRrmFDjAUjQ/hkIVNG+yD/kNsjcYCWa2gtOQPrvWZzDA==
product-id:
imes-product: 4
justauth: justauth:
enabled: true enabled: true
@@ -212,6 +212,9 @@ chenfeng:
#- /rpc-api/system/error-code/* # 错误码的自动创建与下载的接口,无法带上组织编号 #- /rpc-api/system/error-code/* # 错误码的自动创建与下载的接口,无法带上组织编号
#- /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递组织编号;主要解决上传文件的场景,前端不会传递 tenant-id! #- /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递组织编号;主要解决上传文件的场景,前端不会传递 tenant-id!
#- /rpc-api/system/permission/has-any-permissions #- /rpc-api/system/permission/has-any-permissions
ignore-product-urls:
- /admin-api/system/auth/get-permission-info
- /admin-api/system/dict-data/list-all-simple
ignore-tables: ignore-tables:
- system_organization - system_organization
- system_tenant_package - system_tenant_package