fix(auth): standalone auto-login qua IP LAN cua chinh may — _is_local_client (own interface IPs)
This commit is contained in:
+30
-2
@@ -1,6 +1,7 @@
|
||||
import uuid
|
||||
import time
|
||||
import threading
|
||||
import socket
|
||||
from fastapi import APIRouter, HTTPException, Header, Depends, Request, Response
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel, EmailStr
|
||||
@@ -60,6 +61,33 @@ def _is_loopback(host: Optional[str]) -> bool:
|
||||
host = host.lower()
|
||||
return host in ("127.0.0.1", "::1", "localhost") or host.startswith("127.")
|
||||
|
||||
_LOCAL_IPS_CACHE = {"at": 0.0, "ips": set()}
|
||||
|
||||
def _own_interface_ips(max_age=60.0) -> set:
|
||||
"""Các IP interface cua CHINH may (standalone): truy cap qua IP LAN
|
||||
cua may (vd http://192.168.1.12:8000) van la may nay -> auto-login.
|
||||
Client LAN may khac co source IP khac -> khong match -> van can mat khau."""
|
||||
now = time.time()
|
||||
c = _LOCAL_IPS_CACHE
|
||||
if now - c["at"] > max_age:
|
||||
ips = set()
|
||||
try:
|
||||
ips = set(socket.gethostbyname_ex(socket.gethostname())[2])
|
||||
except Exception:
|
||||
pass
|
||||
c["ips"] = {i for i in ips if not _is_loopback(i)}
|
||||
c["at"] = now
|
||||
return c["ips"]
|
||||
|
||||
def _is_local_client(host: Optional[str]) -> bool:
|
||||
"""May chay engine (loopback) hoac IP interface cua chinh may -> local.
|
||||
Dung chung cho get_current_user + /auth/local."""
|
||||
if _is_loopback(host):
|
||||
return True
|
||||
if not host:
|
||||
return False
|
||||
return host in _own_interface_ips()
|
||||
|
||||
def _loopback_admin_user() -> dict:
|
||||
"""Identity admin cho loopback — real user_id từ DB; không bắt buộc đổi
|
||||
mật khẩu (standalone tự vào thẳng DAW)."""
|
||||
@@ -94,7 +122,7 @@ def get_current_user(request: Request, authorization: Optional[str] = Header(Non
|
||||
if not token:
|
||||
# Standalone (loopback): không cần mật khẩu — auto admin. LAN vẫn 401.
|
||||
host = request.client.host if request.client else None
|
||||
if _is_loopback(host):
|
||||
if _is_local_client(host):
|
||||
return _loopback_admin_user()
|
||||
raise HTTPException(status_code=401, detail="Thiếu Token xác thực hoặc Token không hợp lệ")
|
||||
payload = decode_token(token)
|
||||
@@ -168,7 +196,7 @@ async def local_login(request: Request, response: Response):
|
||||
"""Auto-login standalone: chỉ cho phép từ loopback (máy chạy engine).
|
||||
Client LAN nhận 403 → buộc đăng nhập mật khẩu qua /login."""
|
||||
host = request.client.host if request.client else None
|
||||
if not _is_loopback(host):
|
||||
if not _is_local_client(host):
|
||||
raise HTTPException(status_code=403, detail="Truy cập từ xa — cần đăng nhập")
|
||||
u = _loopback_admin_user()
|
||||
token = create_token(u["user_id"], u["username"], u["role"], False)
|
||||
|
||||
Reference in New Issue
Block a user