feat: add cookie sessions and backend role authorization

This commit is contained in:
Backend Contributors
2026-10-16 07:51:59 +08:00
parent 8ac9dcaacb
commit f9827feb1b
28 changed files with 1186 additions and 31 deletions
+49 -2
View File
@@ -9,14 +9,35 @@ from contextlib import contextmanager
from pathlib import Path
import httpx
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.models.auth import User
from app.services.auth import PASSWORD_HASHER
@contextmanager
def server(engine):
def server(engine, *, authenticate=True):
with socket.socket() as socket_:
socket_.bind(("127.0.0.1", 0))
port = socket_.getsockname()[1]
environment = {**os.environ, "DATABASE_URL": engine.url.render_as_string(hide_password=False)}
environment = {
**os.environ,
"DATABASE_URL": engine.url.render_as_string(hide_password=False),
"APP_ENV": "test",
"AUTH_COOKIE_SECURE": "false",
}
if authenticate:
with Session(engine) as db:
if db.scalar(select(User.id).where(User.username == "http_admin")) is None:
db.add(
User(
username="http_admin",
password_hash=PASSWORD_HASHER.hash("test-password-123"),
role="admin",
)
)
db.commit()
backend = Path(__file__).resolve().parents[1]
process = subprocess.Popen(
[
@@ -38,6 +59,7 @@ def server(engine):
)
try:
with httpx.Client(base_url=f"http://127.0.0.1:{port}", timeout=2) as client:
client.headers["Origin"] = "http://localhost:5173"
deadline = time.monotonic() + 15
while time.monotonic() < deadline:
if process.poll() is not None:
@@ -50,6 +72,13 @@ def server(engine):
time.sleep(0.05)
else:
raise AssertionError("默认后端未在时限内就绪")
if authenticate:
login = client.post(
"/api/auth/login",
json={"username": "http_admin", "password": "test-password-123"},
)
assert login.status_code == 200, login.text
client.headers["X-CSRF-Token"] = login.json()["csrf_token"]
yield client
finally:
process.terminate()
@@ -107,3 +136,21 @@ def test_retrieval_run_persists_across_restart(migrated_database):
assert run["results"][0]["knowledge_id"] == item["id"]
with server(migrated_database) as client:
assert client.get(f"/api/retrieval/runs/{run['run_id']}").json() == run
def test_session_and_logout_survive_http_restart(migrated_database):
from app.services.auth import COOKIE_NAME
with server(migrated_database, authenticate=False) as client:
payload = {"username": "http_user", "password": "test-password-123"}
assert client.post("/api/auth/register", json=payload).status_code == 201
response = client.post("/api/auth/login", json=payload)
cookie = client.cookies.get(COOKIE_NAME)
token = response.json()["csrf_token"]
with server(migrated_database, authenticate=False) as client:
client.cookies.set(COOKIE_NAME, cookie)
assert client.get("/api/auth/me").json()["username"] == "http_user"
assert client.post("/api/auth/logout", headers={"X-CSRF-Token": token}).status_code == 204
with server(migrated_database, authenticate=False) as client:
client.cookies.set(COOKIE_NAME, cookie)
assert client.get("/api/auth/me").status_code == 401