feat: implement clean global cross-organization permission node and backend service isolation logic
This commit is contained in:
@ -351,11 +351,20 @@ class BuyInboundService:
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
# 【行级数据隔离】基于 JWT 中的 company_name 进行过滤
|
# 【行级数据隔离】基于 JWT 中的 company_name 进行过滤
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
from flask_jwt_extended import get_jwt
|
||||||
|
|
||||||
claims = get_jwt()
|
claims = get_jwt()
|
||||||
user_role = claims.get('role', '').upper() if claims.get('role') else ''
|
user_role = claims.get('role', '').upper() if claims.get('role') else ''
|
||||||
user_company = claims.get('company_name', '')
|
user_company = claims.get('company_name', '')
|
||||||
|
|
||||||
if user_role != 'SUPER_ADMIN':
|
# 获取用户权限列表(用于检查 global:cross_company 特权)
|
||||||
|
from app.services.auth_service import AuthService
|
||||||
|
user_perms = AuthService.get_user_permissions(user_role) if user_role else []
|
||||||
|
# 合并菜单和元素权限
|
||||||
|
all_perms = user_perms.get('menus', []) + user_perms.get('elements', [])
|
||||||
|
has_cross_company = 'global:cross_company' in all_perms or ('inbound_buy:*' in all_perms)
|
||||||
|
|
||||||
|
if user_role != 'SUPER_ADMIN' and not has_cross_company:
|
||||||
# 【显式拒绝越权】如果前端传了公司参数,且不是当前用户的公司,返回403
|
# 【显式拒绝越权】如果前端传了公司参数,且不是当前用户的公司,返回403
|
||||||
if company and company.strip() and company.strip() != user_company:
|
if company and company.strip() and company.strip() != user_company:
|
||||||
from flask import abort
|
from flask import abort
|
||||||
@ -364,7 +373,7 @@ class BuyInboundService:
|
|||||||
if user_company:
|
if user_company:
|
||||||
query = query.filter(MaterialBase.company_name == user_company)
|
query = query.filter(MaterialBase.company_name == user_company)
|
||||||
else:
|
else:
|
||||||
# 超级管理员:允许跨公司视角
|
# 超级管理员或拥有跨域特权:允许跨公司视角
|
||||||
if company and company.strip():
|
if company and company.strip():
|
||||||
query = query.filter(MaterialBase.company_name == company.strip())
|
query = query.filter(MaterialBase.company_name == company.strip())
|
||||||
|
|
||||||
|
|||||||
@ -203,9 +203,26 @@ const fetchTree = async () => {
|
|||||||
try {
|
try {
|
||||||
const res: any = await getAllPermissionTree()
|
const res: any = await getAllPermissionTree()
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
rawTreeData.value = res.data
|
// --- 注入全局特权虚拟节点 ---
|
||||||
// 初始化表格结构(此时没有勾选状态)
|
const globalNode = {
|
||||||
tableData.value = transformData(res.data)
|
id: 99999, // 虚拟ID
|
||||||
|
name: '🌍 全局系统特权',
|
||||||
|
code: 'global_privileges',
|
||||||
|
type: 'menu',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 999991,
|
||||||
|
name: '跨组织/跨区域数据查询',
|
||||||
|
code: 'global:cross_company',
|
||||||
|
type: 'element'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
// 将虚拟节点放在最前面,然后交给 transformData 处理
|
||||||
|
const rawData = [globalNode, ...(res.data || [])];
|
||||||
|
|
||||||
|
rawTreeData.value = rawData;
|
||||||
|
tableData.value = transformData(rawData);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ElMessage.error('加载权限配置失败')
|
ElMessage.error('加载权限配置失败')
|
||||||
|
|||||||
Reference in New Issue
Block a user