fix: Fail-Closed 字段级安全加固 — 堵住15+端点价格泄露
## stock.py
- _make_price_stripper(): 工厂函数,选单前缀自动剥离所有价格/成本字段
- _do_get_stock_list(permission_prefix): 每个item.to_dict()后剥离价格
- /all 端点: 非AI模式自动剥离价格字段
- /list 端点: permission_prefix='outbound_selection' 传递
## outbound.py
- /bom-match-stock: 返回前按stock_type剥离全部价格/成本字段
- /scan: result.pop('price', None)
## scrap.py
- /scan: result.pop('price', None)
- /records: 每条记录剥离 cost_at_scrap, total_loss
## transactions.py
- filter_item_by_permissions: 从空字典恢复完整20字段映射
- /borrow/stock-list: permission_prefix='op_borrow_apply' 传递
## buy.py / semi.py / product.py
- submit 成功响应剥离所有价格/成本字段(不泄露给前端)
## bom.py
- /base/list: 剥离 referencePrice
This commit is contained in:
@ -44,23 +44,33 @@ def get_current_user_info():
|
||||
def filter_item_by_permissions(item_dict, user_permissions, prefix='op_records'):
|
||||
"""
|
||||
根据用户权限过滤 item 字典,无权限的字段值置为 None
|
||||
|
||||
★ Fail-Closed: 字段映射默认为完整列表,不再为空字典。
|
||||
"""
|
||||
# 字段名到权限码的映射(与前端 permissionMap 保持一致)
|
||||
field_to_perm = {
|
||||
# 'borrow_no': f'{prefix}:borrow_no',
|
||||
# 'borrower_name': f'{prefix}:borrower_name',
|
||||
# 'sku': f'{prefix}:sku',
|
||||
# 'borrow_time': f'{prefix}:borrow_time',
|
||||
# 'return_time': f'{prefix}:return_time',
|
||||
# 'return_operator': f'{prefix}:return_operator',
|
||||
# 'status': f'{prefix}:status',
|
||||
# 'expected_return_time': f'{prefix}:expected_return_time',
|
||||
# 'return_location': f'{prefix}:return_location',
|
||||
# 'borrow_signature': f'{prefix}:borrow_signature',
|
||||
# 'return_signature': f'{prefix}:return_signature',
|
||||
'id': f'{prefix}:id',
|
||||
'borrow_no': f'{prefix}:borrow_no',
|
||||
'borrower_name': f'{prefix}:borrower_name',
|
||||
'sku': f'{prefix}:sku',
|
||||
'source_table': f'{prefix}:source_table',
|
||||
'stock_id': f'{prefix}:stock_id',
|
||||
'barcode': f'{prefix}:barcode',
|
||||
'quantity': f'{prefix}:quantity',
|
||||
'returned_quantity': f'{prefix}:returned_quantity',
|
||||
'borrow_time': f'{prefix}:borrow_time',
|
||||
'return_time': f'{prefix}:return_time',
|
||||
'return_operator': f'{prefix}:return_operator',
|
||||
'return_location': f'{prefix}:return_location',
|
||||
'status': f'{prefix}:status',
|
||||
'expected_return_time': f'{prefix}:expected_return_time',
|
||||
'borrow_signature': f'{prefix}:borrow_signature',
|
||||
'return_signature': f'{prefix}:return_signature',
|
||||
'remark': f'{prefix}:remark',
|
||||
'material_name': f'{prefix}:material_name',
|
||||
'is_returned': f'{prefix}:is_returned',
|
||||
'current_location': f'{prefix}:current_location',
|
||||
}
|
||||
# 如果用户是超级管理员且有 '*',则不过滤
|
||||
if '*' in user_permissions:
|
||||
if '*' in user_permissions or f'{prefix}:*' in user_permissions:
|
||||
return item_dict
|
||||
for field, perm_code in field_to_perm.items():
|
||||
if field in item_dict and perm_code not in user_permissions:
|
||||
@ -290,9 +300,9 @@ def get_borrow_request_list():
|
||||
@jwt_required()
|
||||
@permission_required('op_borrow_apply')
|
||||
def get_borrow_stock_list():
|
||||
"""借库选单专用库存列表,与出库选单共享底层逻辑"""
|
||||
"""借库选单专用库存列表 — Fail-Closed: 剥离价格字段"""
|
||||
from app.api.v1.inbound.stock import _do_get_stock_list
|
||||
return _do_get_stock_list()
|
||||
return _do_get_stock_list(permission_prefix='op_borrow_apply')
|
||||
|
||||
|
||||
# --- 执行借库扣减(审批通过后调用)---
|
||||
|
||||
Reference in New Issue
Block a user