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 uuid
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
import socket
|
||||||
from fastapi import APIRouter, HTTPException, Header, Depends, Request, Response
|
from fastapi import APIRouter, HTTPException, Header, Depends, Request, Response
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from pydantic import BaseModel, EmailStr
|
from pydantic import BaseModel, EmailStr
|
||||||
@@ -60,6 +61,33 @@ def _is_loopback(host: Optional[str]) -> bool:
|
|||||||
host = host.lower()
|
host = host.lower()
|
||||||
return host in ("127.0.0.1", "::1", "localhost") or host.startswith("127.")
|
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:
|
def _loopback_admin_user() -> dict:
|
||||||
"""Identity admin cho loopback — real user_id từ DB; không bắt buộc đổi
|
"""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)."""
|
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:
|
if not token:
|
||||||
# Standalone (loopback): không cần mật khẩu — auto admin. LAN vẫn 401.
|
# 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
|
host = request.client.host if request.client else None
|
||||||
if _is_loopback(host):
|
if _is_local_client(host):
|
||||||
return _loopback_admin_user()
|
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ệ")
|
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)
|
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).
|
"""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."""
|
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
|
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")
|
raise HTTPException(status_code=403, detail="Truy cập từ xa — cần đăng nhập")
|
||||||
u = _loopback_admin_user()
|
u = _loopback_admin_user()
|
||||||
token = create_token(u["user_id"], u["username"], u["role"], False)
|
token = create_token(u["user_id"], u["username"], u["role"], False)
|
||||||
|
|||||||
Reference in New Issue
Block a user