diff --git a/inventory-backend/app/services/auth_service.py b/inventory-backend/app/services/auth_service.py index 70ed46d..07c865b 100644 --- a/inventory-backend/app/services/auth_service.py +++ b/inventory-backend/app/services/auth_service.py @@ -104,6 +104,8 @@ class AuthService: user_id = user.id user_info = user.to_dict() user_info['role'] = user_role + # 获取用户所属公司(存于 department 字段) + user_company = user.department or '' # 3. 生成 Token # Token 中 identity 存数据库ID,claims 存登录账号ID @@ -115,7 +117,8 @@ class AuthService: additional_claims={ 'role': user_role, 'username': account_id, # 存纯账号ID - 'display_name': user_info.get('username') # 存显示名 + 'display_name': user_info.get('username'), # 存显示名 + 'company_name': user_company # 存所属公司 } ) @@ -125,7 +128,8 @@ class AuthService: additional_claims={ 'role': user_role, 'username': account_id, - 'display_name': user_info.get('display_name', account_id) + 'display_name': user_info.get('display_name', account_id), + 'company_name': user_company } ) diff --git a/inventory-backend/app/services/inbound/base_service.py b/inventory-backend/app/services/inbound/base_service.py index 25bfaa2..f2e96de 100644 --- a/inventory-backend/app/services/inbound/base_service.py +++ b/inventory-backend/app/services/inbound/base_service.py @@ -1,5 +1,6 @@ # 文件路径: app/services/inbound/base_service.py +from flask_jwt_extended import get_jwt from app.extensions import db from app.models.base import MaterialBase, MaterialWarningSetting from app.models.inbound.buy import StockBuy @@ -209,9 +210,26 @@ class MaterialBaseService: MaterialBase.spec_model.ilike(kw) )) - company = filters.get('company') - if company is not None and company != '': - query = query.filter(MaterialBase.company_name.ilike(company.strip())) + # ============================================================ + # 【行级数据隔离】基于 JWT 中的 company_name 进行过滤 + # ============================================================ + claims = get_jwt() + user_role = claims.get('role', '').upper() if claims.get('role') else '' + user_company = claims.get('company_name', '') + + # 获取前端传的查询参数 + req_company = filters.get('company') if filters else None + + if user_role != 'SUPER_ADMIN': + # 普通用户:强制隔离!无视前端传的 company 参数 + if user_company: + query = query.filter(MaterialBase.company_name == user_company) + # 如果用户没有所属公司字段,则只显示公司为空的记录(或不允许查看) + else: + # 超级管理员:允许跨公司视角 + if req_company: + query = query.filter(MaterialBase.company_name == req_company) + # 超管没选公司则不加过滤,看到全量 category = filters.get('category') if category is not None and category != '': @@ -618,9 +636,23 @@ class MaterialBaseService: MaterialBase.spec_model.ilike(kw), MaterialBase.company_name.ilike(kw) )) - company = filters.get('company') - if company is not None and company != '': - filter_conditions.append(MaterialBase.company_name.ilike(company.strip())) + # ============================================================ + # 【行级数据隔离】基于 JWT 中的 company_name 进行过滤(高级筛选) + # ============================================================ + claims = get_jwt() + user_role = claims.get('role', '').upper() if claims.get('role') else '' + user_company = claims.get('company_name', '') + req_company = filters.get('company') if filters else None + + if user_role != 'SUPER_ADMIN': + # 普通用户:强制隔离 + if user_company: + filter_conditions.append(MaterialBase.company_name == user_company) + else: + # 超级管理员:允许跨公司视角 + if req_company: + filter_conditions.append(MaterialBase.company_name == req_company) + category = filters.get('category') if category is not None and category != '': filter_conditions.append(MaterialBase.category.ilike(category.strip())) diff --git a/inventory-backend/app/services/inbound/buy_service.py b/inventory-backend/app/services/inbound/buy_service.py index 052db7e..f0808dd 100644 --- a/inventory-backend/app/services/inbound/buy_service.py +++ b/inventory-backend/app/services/inbound/buy_service.py @@ -1,4 +1,5 @@ # inventory-backend/app/services/inbound/buy_service.py +from flask_jwt_extended import get_jwt from app.extensions import db from app.models.inbound.buy import StockBuy from app.models.inbound.product import StockProduct @@ -347,9 +348,21 @@ class BuyInboundService: if material_type and material_type.strip(): query = query.filter(MaterialBase.material_type == material_type.strip()) - # 3.1 公司独立搜索 [新增] - if company and company.strip(): - query = query.filter(MaterialBase.company_name == company.strip()) + # ============================================================ + # 【行级数据隔离】基于 JWT 中的 company_name 进行过滤 + # ============================================================ + claims = get_jwt() + user_role = claims.get('role', '').upper() if claims.get('role') else '' + user_company = claims.get('company_name', '') + + if user_role != 'SUPER_ADMIN': + # 普通用户:强制隔离!无视前端传的 company 参数 + if user_company: + query = query.filter(MaterialBase.company_name == user_company) + else: + # 超级管理员:允许跨公司视角 + if company and company.strip(): + query = query.filter(MaterialBase.company_name == company.strip()) # 4. 状态筛选 if not statuses: statuses = ['在库', '借库']