Device-id SSO: account sets did, signals login via Redis
- Factory: set {name}_did cookie for all apps (including account)
via before_request/after_request hooks (g.device_id always available)
- Factory: _check_auth_state checks did_auth:{account_did} in Redis
to override stale "not logged in" cache when account login detected
- OAuth: removed _ensure_device_cookie (moved to factory), callback
stores account_did from authorize redirect in session
- OAuth: login uses g.device_id, logout clears _account_did
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import secrets
|
||||
from pathlib import Path
|
||||
from typing import Callable, Awaitable, Sequence
|
||||
|
||||
@@ -107,6 +108,29 @@ def create_base_app(
|
||||
from shared.infrastructure.oauth import create_oauth_blueprint
|
||||
app.register_blueprint(create_oauth_blueprint(name))
|
||||
|
||||
# --- device id (all apps, including account) ---
|
||||
_did_cookie = f"{name}_did"
|
||||
|
||||
@app.before_request
|
||||
async def _init_device_id():
|
||||
did = request.cookies.get(_did_cookie)
|
||||
if did:
|
||||
g.device_id = did
|
||||
g._new_device_id = False
|
||||
else:
|
||||
g.device_id = secrets.token_urlsafe(32)
|
||||
g._new_device_id = True
|
||||
|
||||
@app.after_request
|
||||
async def _set_device_cookie(response):
|
||||
if getattr(g, "_new_device_id", False):
|
||||
response.set_cookie(
|
||||
_did_cookie, g.device_id,
|
||||
max_age=30 * 24 * 3600,
|
||||
secure=True, samesite="Lax", httponly=True,
|
||||
)
|
||||
return response
|
||||
|
||||
# --- before-request hooks ---
|
||||
@app.before_request
|
||||
async def _route_log():
|
||||
@@ -176,10 +200,25 @@ def create_base_app(
|
||||
if request.headers.get("HX-Request"):
|
||||
return
|
||||
import time as _time
|
||||
now = _time.time()
|
||||
pnone_at = qs.get("_pnone_at")
|
||||
if pnone_at and (_time.time() - pnone_at) < 300:
|
||||
|
||||
# Check if account signalled a login after we cached "not logged in"
|
||||
account_did = qs.get("_account_did")
|
||||
if account_did and redis and pnone_at:
|
||||
auth_ts = await redis.get(f"did_auth:{account_did}")
|
||||
if auth_ts:
|
||||
try:
|
||||
if float(auth_ts) > pnone_at:
|
||||
# Login on account after our cache — re-check now
|
||||
qs.pop("_pnone_at", None)
|
||||
return redirect(f"/auth/login?prompt=none&next={_quote(request.url, safe='')}")
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if pnone_at and (now - pnone_at) < 300:
|
||||
return
|
||||
device_id = request.cookies.get(f"{name}_did")
|
||||
device_id = g.device_id
|
||||
if device_id and redis:
|
||||
cached = await redis.get(f"prompt:{name}:{device_id}")
|
||||
if cached == b"none":
|
||||
|
||||
Reference in New Issue
Block a user