mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 03:10:46 +08:00
feat(auth): add local login, audit, API keys, and system admin UI
Gate netx Web/API/WebCRT with JWT and per-user API tokens, bootstrap an admin with forced password change, and expose users/audit/API-key management under a System section. MCP can reuse data/auth/mcp_token without extra env for local labs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
14f14d34bd
commit
6d4cd741ef
35 changed files with 2699 additions and 21 deletions
|
|
@ -11,7 +11,9 @@ from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket, WebSo
|
|||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .db import get_db
|
||||
from .db import SessionLocal, get_db
|
||||
from .auth_deps import resolve_user_from_token
|
||||
from .config import settings
|
||||
from .webcrt_service import (
|
||||
close_session,
|
||||
create_session,
|
||||
|
|
@ -74,6 +76,23 @@ def api_close_session(session_id: str, request: Request) -> dict[str, Any]:
|
|||
|
||||
@router.websocket("/sessions/{session_id}/ws")
|
||||
async def websocket_session(websocket: WebSocket, session_id: str) -> None:
|
||||
if bool(settings.auth_enabled):
|
||||
token = str(websocket.query_params.get("access_token") or "").strip()
|
||||
if not token:
|
||||
auth = str(websocket.headers.get("authorization") or "").strip()
|
||||
if auth.lower().startswith("bearer "):
|
||||
token = auth[7:].strip()
|
||||
db = SessionLocal()
|
||||
try:
|
||||
resolved = resolve_user_from_token(db, token) if token else None
|
||||
finally:
|
||||
db.close()
|
||||
if resolved is None:
|
||||
await websocket.close(code=4401)
|
||||
return
|
||||
websocket.state.auth_user = resolved[0]
|
||||
websocket.state.auth_via = resolved[1]
|
||||
|
||||
await websocket.accept()
|
||||
attach_gen = 0
|
||||
try:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue