```
feat(auth): 添加用户权限获取接口并完善JWT令牌角色信息 - 在JWT令牌中添加用户角色信息 - 新增get_my_permissions接口用于获取当前用户权限码列表 - 重构认证回调逻辑,增加错误日志记录 - 更新用户信息获取接口使用Authorization头验证 ```
This commit is contained in:
+118
-18
@@ -1,8 +1,10 @@
|
||||
"""OLT 设备管理 API"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import distinct
|
||||
from pydantic import BaseModel
|
||||
from app.core.database import get_db
|
||||
from app.middleware.permission_middleware import require_permission
|
||||
from app.models.device import OLTDevice
|
||||
import pandas as pd
|
||||
import io
|
||||
@@ -15,6 +17,7 @@ class OLTCreate(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
slot_command: str = "display onu slot"
|
||||
region: str = "城区"
|
||||
location: str = ""
|
||||
description: str = ""
|
||||
|
||||
@@ -23,17 +26,57 @@ class OLTEdit(BaseModel):
|
||||
username: str
|
||||
password: str = None
|
||||
slot_command: str = "display onu slot"
|
||||
region: str = "城区"
|
||||
location: str = ""
|
||||
description: str = ""
|
||||
|
||||
|
||||
@router.get("/regions")
|
||||
def get_olt_regions(
|
||||
db: Session = Depends(get_db),
|
||||
current: dict = Depends(require_permission('olt.view')),
|
||||
):
|
||||
"""获取 OLT 设备的所有区域(受角色数据范围限制)"""
|
||||
query = db.query(distinct(OLTDevice.region)).filter(
|
||||
OLTDevice.region.isnot(None),
|
||||
OLTDevice.region != ''
|
||||
)
|
||||
if current.get('role') == 'area_admin' and current.get('assigned_area'):
|
||||
areas = [a.strip() for a in current['assigned_area'].split(',') if a.strip()]
|
||||
if areas:
|
||||
query = query.filter(OLTDevice.region.in_(areas))
|
||||
else:
|
||||
return []
|
||||
return sorted([r[0] for r in query.all()])
|
||||
|
||||
|
||||
@router.get("/devices")
|
||||
def get_devices(db: Session = Depends(get_db)):
|
||||
return db.query(OLTDevice).all()
|
||||
def get_devices(
|
||||
db: Session = Depends(get_db),
|
||||
current: dict = Depends(require_permission('olt.view')),
|
||||
):
|
||||
q = db.query(OLTDevice)
|
||||
# 区域管理员只能看自己区域的 OLT
|
||||
if current.get('role') == 'area_admin' and current.get('assigned_area'):
|
||||
areas = [a.strip() for a in current['assigned_area'].split(',') if a.strip()]
|
||||
if areas:
|
||||
q = q.filter(OLTDevice.region.in_(areas))
|
||||
else:
|
||||
return []
|
||||
return q.all()
|
||||
|
||||
|
||||
@router.post("/devices")
|
||||
def create_device(device: OLTCreate, db: Session = Depends(get_db)):
|
||||
def create_device(
|
||||
device: OLTCreate,
|
||||
db: Session = Depends(get_db),
|
||||
current: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
# 区域管理员只能创建自己区域的 OLT
|
||||
if current.get('role') == 'area_admin' and current.get('assigned_area'):
|
||||
areas = [a.strip() for a in current['assigned_area'].split(',') if a.strip()]
|
||||
if device.region not in areas:
|
||||
raise HTTPException(status_code=403, detail="只能管理本区域的 OLT")
|
||||
db_device = OLTDevice(**device.dict())
|
||||
db.add(db_device)
|
||||
db.commit()
|
||||
@@ -41,15 +84,26 @@ def create_device(device: OLTCreate, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.put("/devices/{ip_address}")
|
||||
def update_device(ip_address: str, device: OLTEdit, db: Session = Depends(get_db)):
|
||||
def update_device(
|
||||
ip_address: str,
|
||||
device: OLTEdit,
|
||||
db: Session = Depends(get_db),
|
||||
current: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
db_device = db.query(OLTDevice).filter(OLTDevice.ip_address == ip_address).first()
|
||||
if not db_device:
|
||||
raise HTTPException(status_code=404, detail="设备不存在")
|
||||
# 区域管理员只能管理自己区域的 OLT
|
||||
if current.get('role') == 'area_admin' and current.get('assigned_area'):
|
||||
areas = [a.strip() for a in current['assigned_area'].split(',') if a.strip()]
|
||||
if db_device.region not in areas:
|
||||
raise HTTPException(status_code=403, detail="只能管理本区域的 OLT")
|
||||
|
||||
db_device.username = device.username
|
||||
if device.password:
|
||||
db_device.password = device.password
|
||||
db_device.slot_command = device.slot_command
|
||||
db_device.region = device.region
|
||||
db_device.location = device.location
|
||||
db_device.description = device.description
|
||||
|
||||
@@ -58,14 +112,21 @@ def update_device(ip_address: str, device: OLTEdit, db: Session = Depends(get_db
|
||||
|
||||
|
||||
@router.delete("/devices/{ip_address}")
|
||||
def delete_device(ip_address: str, db: Session = Depends(get_db)):
|
||||
def delete_device(
|
||||
ip_address: str,
|
||||
db: Session = Depends(get_db),
|
||||
current: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
from app.models.device import ONUDevice
|
||||
|
||||
device = db.query(OLTDevice).filter(OLTDevice.ip_address == ip_address).first()
|
||||
if not device:
|
||||
raise HTTPException(status_code=404, detail="设备不存在")
|
||||
if current.get('role') == 'area_admin' and current.get('assigned_area'):
|
||||
areas = [a.strip() for a in current['assigned_area'].split(',') if a.strip()]
|
||||
if device.region not in areas:
|
||||
raise HTTPException(status_code=403, detail="只能管理本区域的 OLT")
|
||||
|
||||
# 检查是否有关联的 ONU 设备
|
||||
onu_count = db.query(ONUDevice).filter(ONUDevice.olt_id == device.id).count()
|
||||
if onu_count > 0:
|
||||
raise HTTPException(status_code=400, detail=f"该 OLT 设备下还有 {onu_count} 个 ONU 设备,无法删除")
|
||||
@@ -76,7 +137,11 @@ def delete_device(ip_address: str, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/import")
|
||||
async def import_devices(file: UploadFile = File(...), db: Session = Depends(get_db)):
|
||||
async def import_devices(
|
||||
file: UploadFile = File(...),
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
try:
|
||||
content = await file.read()
|
||||
df = pd.read_excel(io.BytesIO(content))
|
||||
@@ -118,7 +183,7 @@ async def import_devices(file: UploadFile = File(...), db: Session = Depends(get
|
||||
|
||||
|
||||
@router.get("/template")
|
||||
def download_template():
|
||||
def download_template(_: dict = Depends(require_permission('olt.manage'))):
|
||||
from fastapi.responses import FileResponse
|
||||
return FileResponse(
|
||||
path="/home/v6ole/pyproject/H3ConuMS2/backend/templates/OLT设备导入模板.xlsx",
|
||||
@@ -127,7 +192,11 @@ def download_template():
|
||||
|
||||
|
||||
@router.get("/duplicate-macs")
|
||||
def get_duplicate_macs(olt_id: int = None, db: Session = Depends(get_db)):
|
||||
def get_duplicate_macs(
|
||||
olt_id: int = None,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.view')),
|
||||
):
|
||||
"""查询重复 MAC 地址记录"""
|
||||
from app.models.device import DuplicateMac
|
||||
query = db.query(DuplicateMac)
|
||||
@@ -148,7 +217,11 @@ def get_duplicate_macs(olt_id: int = None, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.delete("/duplicate-macs/{record_id}")
|
||||
def delete_duplicate_mac(record_id: int, db: Session = Depends(get_db)):
|
||||
def delete_duplicate_mac(
|
||||
record_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
"""删除重复 MAC 记录(已处理后清除)"""
|
||||
from app.models.device import DuplicateMac
|
||||
record = db.query(DuplicateMac).filter(DuplicateMac.id == record_id).first()
|
||||
@@ -164,7 +237,12 @@ class ClearPortRequest(BaseModel):
|
||||
|
||||
|
||||
@router.post("/duplicate-macs/{record_id}/clear-port")
|
||||
def clear_onu_port(record_id: int, body: ClearPortRequest, db: Session = Depends(get_db)):
|
||||
def clear_onu_port(
|
||||
record_id: int,
|
||||
body: ClearPortRequest,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
"""通过 SSH 清除指定端口的 ONU 配置,并从 ports 列表中移除该端口"""
|
||||
from app.models.device import DuplicateMac
|
||||
from app.services.ssh_service import SSHService
|
||||
@@ -204,7 +282,10 @@ def clear_onu_port(record_id: int, body: ClearPortRequest, db: Session = Depends
|
||||
|
||||
|
||||
@router.get("/new-devices")
|
||||
def get_new_devices(db: Session = Depends(get_db)):
|
||||
def get_new_devices(
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.view')),
|
||||
):
|
||||
"""查询新发现的设备列表(待补全信息)"""
|
||||
from app.models.device import NewDevice, ONUDevice
|
||||
rows = (
|
||||
@@ -241,7 +322,12 @@ class NewDeviceUpdate(BaseModel):
|
||||
|
||||
|
||||
@router.put("/new-devices/{record_id}")
|
||||
def update_new_device(record_id: int, body: NewDeviceUpdate, db: Session = Depends(get_db)):
|
||||
def update_new_device(
|
||||
record_id: int,
|
||||
body: NewDeviceUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
"""补全新设备信息,完成后从 new_devices 移除"""
|
||||
from app.models.device import NewDevice, ONUDevice
|
||||
record = db.query(NewDevice).filter(NewDevice.id == record_id).first()
|
||||
@@ -265,7 +351,11 @@ def update_new_device(record_id: int, body: NewDeviceUpdate, db: Session = Depen
|
||||
|
||||
|
||||
@router.delete("/new-devices/{record_id}")
|
||||
def dismiss_new_device(record_id: int, db: Session = Depends(get_db)):
|
||||
def dismiss_new_device(
|
||||
record_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.manage')),
|
||||
):
|
||||
"""忽略新设备(不补全信息,仅从待处理列表移除)"""
|
||||
from app.models.device import NewDevice
|
||||
record = db.query(NewDevice).filter(NewDevice.id == record_id).first()
|
||||
@@ -277,7 +367,10 @@ def dismiss_new_device(record_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/quick-scan")
|
||||
def quick_scan(db: Session = Depends(get_db)):
|
||||
def quick_scan(
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.discover')),
|
||||
):
|
||||
"""多线程对所有 OLT 同时执行扫描,更新已有设备状态"""
|
||||
from app.services.check_service import CheckService
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
@@ -339,7 +432,10 @@ def quick_scan(db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/loopback-detection")
|
||||
def loopback_detection(db: Session = Depends(get_db)):
|
||||
def loopback_detection(
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.loopback')),
|
||||
):
|
||||
"""对所有 OLT 并发执行环路检测,返回有环路的端口及对应设备信息"""
|
||||
from app.models.device import ONUDevice
|
||||
from app.services.ssh_service import SSHService
|
||||
@@ -407,7 +503,11 @@ class TogglePortRequest(BaseModel):
|
||||
|
||||
|
||||
@router.get("/devices/{olt_id}/ports")
|
||||
def get_olt_ports(olt_id: int, db: Session = Depends(get_db)):
|
||||
def get_olt_ports(
|
||||
olt_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('olt.port_manage')),
|
||||
):
|
||||
"""获取指定 OLT 的所有 Olt 端口状态"""
|
||||
from app.services.ssh_service import SSHService
|
||||
olt = db.query(OLTDevice).filter(OLTDevice.id == olt_id).first()
|
||||
@@ -425,7 +525,7 @@ def get_olt_ports(olt_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/devices/{olt_id}/ports/toggle")
|
||||
def toggle_olt_port(olt_id: int, body: TogglePortRequest, port_name: str, db: Session = Depends(get_db)):
|
||||
def toggle_olt_port(olt_id: int, body: TogglePortRequest, port_name: str, db: Session = Depends(get_db), _: dict = Depends(require_permission('olt.port_manage'))):
|
||||
"""开启或关闭指定 OLT 端口"""
|
||||
from app.services.ssh_service import SSHService
|
||||
if body.action not in ("shutdown", "undo shutdown"):
|
||||
|
||||
Reference in New Issue
Block a user