feat: 站点 URL 白名单/黑名单管理 API
- GET/POST /admin/site/url-rules、DELETE /admin/site/url-rules?rule_type&host - 存储于 site.url_whitelist / site.url_blacklist(SystemConfig,公共 /site/config 可读) - 域名规范化校验;写审计
This commit is contained in:
@@ -11,7 +11,7 @@ from fastapi import APIRouter, Depends, File, HTTPException, Request, Response,
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..dependencies import get_db
|
||||
from ..schemas.operator import TaskCreateRequest, TaskUpdateRequest, TaskStatusRequest, TaskAssignRequest, TaskRecommendRequest, TaskSelectRecommendRequest, ProviderCreateRequest, ProviderUpdateRequest, ContentCreateRequest, ContentStatusRequest, ContentUpdateRequest, ContentReviewRequest, ConfigUpdateRequest, ComputePingResponse, ComputeBalanceRequest, ComputeProvisionRequest, ComputeProvisionResponse, CourseCreateRequest, CourseStatusRequest, CourseUpdateRequest, ActivityCreateRequest, ActivityStatusRequest, ActivityUpdateRequest, BookingUpdateRequest, TestCreateRequest, TestStatusRequest
|
||||
from ..schemas.operator import TaskCreateRequest, TaskUpdateRequest, TaskStatusRequest, TaskAssignRequest, TaskRecommendRequest, TaskSelectRecommendRequest, ProviderCreateRequest, ProviderUpdateRequest, ContentCreateRequest, ContentStatusRequest, ContentUpdateRequest, ContentReviewRequest, ConfigUpdateRequest, UrlRuleRequest, ComputePingResponse, ComputeBalanceRequest, ComputeProvisionRequest, ComputeProvisionResponse, CourseCreateRequest, CourseStatusRequest, CourseUpdateRequest, ActivityCreateRequest, ActivityStatusRequest, ActivityUpdateRequest, BookingUpdateRequest, TestCreateRequest, TestStatusRequest
|
||||
from ...rbac import require_permission, require_roles, write_audit
|
||||
from ...infrastructure.repositories import Database
|
||||
from ...services import compute_client
|
||||
@@ -619,6 +619,93 @@ async def list_config(
|
||||
return await db.config.all()
|
||||
|
||||
|
||||
|
||||
# ── 站点 URL 白名单 / 黑名单(应用内网页容器认证标识)──────────────────────
|
||||
URL_WHITELIST_KEY = "site.url_whitelist"
|
||||
URL_BLACKLIST_KEY = "site.url_blacklist"
|
||||
|
||||
|
||||
def _split_host_list(raw: str | None) -> list[str]:
|
||||
if not raw:
|
||||
return []
|
||||
return [
|
||||
h for h in (x.strip() for x in raw.replace(",", ",").split(",")) if h
|
||||
]
|
||||
|
||||
|
||||
def _normalize_host(host: str) -> str:
|
||||
h = host.strip().lower()
|
||||
h = h.replace("https://", "").replace("http://", "")
|
||||
h = h.split("/")[0].split(":")[0].strip()
|
||||
if not h or any(ch.isspace() for ch in h):
|
||||
raise HTTPException(status_code=422, detail="域名格式不正确")
|
||||
return h
|
||||
|
||||
|
||||
async def _get_url_rules(db: Database) -> dict:
|
||||
return {
|
||||
"whitelist": _split_host_list(await db.config.get(URL_WHITELIST_KEY)),
|
||||
"blacklist": _split_host_list(await db.config.get(URL_BLACKLIST_KEY)),
|
||||
}
|
||||
|
||||
|
||||
async def _save_url_rules(db: Database, rules: dict) -> None:
|
||||
await db.config.set(URL_WHITELIST_KEY, ",".join(rules["whitelist"]),
|
||||
description="应用内网页容器白名单(域名)")
|
||||
await db.config.set(URL_BLACKLIST_KEY, ",".join(rules["blacklist"]),
|
||||
description="应用内网页容器黑名单(域名,命中禁止打开)")
|
||||
|
||||
|
||||
@router.get("/site/url-rules", summary="站点 URL 白名单/黑名单列表")
|
||||
async def list_url_rules(
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("operator")),
|
||||
):
|
||||
return await _get_url_rules(db)
|
||||
|
||||
|
||||
@router.post("/site/url-rules", summary="新增白名单/黑名单域名")
|
||||
async def add_url_rule(
|
||||
req: UrlRuleRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_permission("action:config.manage")),
|
||||
):
|
||||
if req.rule_type not in ("whitelist", "blacklist"):
|
||||
raise HTTPException(status_code=422, detail="rule_type 仅支持 whitelist/blacklist")
|
||||
host = _normalize_host(req.host)
|
||||
rules = await _get_url_rules(db)
|
||||
key = req.rule_type
|
||||
if host in rules[key]:
|
||||
raise HTTPException(status_code=409, detail="该域名已在名单中")
|
||||
rules[key].append(host)
|
||||
await _save_url_rules(db, rules)
|
||||
await write_audit(db, action="url_rule.add", resource="site", resource_id=f"{key}:{host}",
|
||||
detail=req.host, user=actor, request=request)
|
||||
return rules
|
||||
|
||||
|
||||
@router.delete("/site/url-rules", summary="删除白名单/黑名单域名")
|
||||
async def remove_url_rule(
|
||||
rule_type: str,
|
||||
host: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_permission("action:config.manage")),
|
||||
):
|
||||
if rule_type not in ("whitelist", "blacklist"):
|
||||
raise HTTPException(status_code=422, detail="rule_type 仅支持 whitelist/blacklist")
|
||||
host = _normalize_host(host)
|
||||
rules = await _get_url_rules(db)
|
||||
key = rule_type
|
||||
if host not in rules[key]:
|
||||
raise HTTPException(status_code=404, detail="该域名不在名单中")
|
||||
rules[key].remove(host)
|
||||
await _save_url_rules(db, rules)
|
||||
await write_audit(db, action="url_rule.remove", resource="site", resource_id=f"{key}:{host}",
|
||||
detail=host, user=actor, request=request)
|
||||
return rules
|
||||
|
||||
@router.put("/config/{key}", summary="更新系统配置")
|
||||
async def set_config(
|
||||
key: str,
|
||||
|
||||
@@ -164,6 +164,12 @@ class ConfigUpdateRequest(BaseModel):
|
||||
description: str = ""
|
||||
|
||||
|
||||
class UrlRuleRequest(BaseModel):
|
||||
"""站点 URL 白名单 / 黑名单单条操作。"""
|
||||
rule_type: str # whitelist | blacklist
|
||||
host: str
|
||||
|
||||
|
||||
# ── 任务管理 ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user