feat(auth): 后台登录改为滑动会话

- JWT 记录 iat,exp=min(now+24h, iat+7d)
- 已认证请求自动续签 httpOnly Cookie
- 新增 ACCESS_TOKEN_IDLE_HOURS / ACCESS_TOKEN_MAX_HOURS
This commit is contained in:
yml2213
2026-10-25 14:07:44 +08:00
parent 935be7a613
commit 6fc453017c
9 changed files with 378 additions and 35 deletions
+6 -22
View File
@@ -2,8 +2,6 @@
from __future__ import annotations
import os
from fastapi import APIRouter, Depends, Request, Response
from sqlalchemy.orm import Session
@@ -21,7 +19,7 @@ from ..schemas import (
SmsCodeResponse,
TokenResponse,
)
from ..security import ACCESS_TOKEN_EXPIRE_HOURS, create_access_token, verify_password
from ..security import issue_access_token, verify_password
from ..services.dc_auth_service import (
APP_ID,
CHALLENGE_PURPOSE,
@@ -37,12 +35,10 @@ from ..services.login_sms_service import (
send_login_sms_code,
verify_login_sms_code,
)
from ..session import clear_session_cookie, set_session_cookie
router = APIRouter(prefix="/api/auth", tags=["认证"])
# Cookie 安全配置(生产环境 HTTPS 部署时设置 COOKIE_SECURE=true)
_COOKIE_SECURE = os.getenv("COOKIE_SECURE", "false").lower() == "true"
def _find_user(db: Session, username_value: str) -> User | None:
"""用户名只 trim,不做大小写折叠、不限制字符集。
@@ -75,18 +71,6 @@ def _request_origin(request: Request) -> str:
return str(request.base_url).rstrip("/")
def _set_auth_cookie(response: Response, token: str) -> None:
response.set_cookie(
key="access_token",
value=token,
httponly=True,
secure=_COOKIE_SECURE,
samesite="lax",
max_age=ACCESS_TOKEN_EXPIRE_HOURS * 3600,
path="/",
)
def _issue_session(
db: Session,
response: Response,
@@ -94,8 +78,8 @@ def _issue_session(
method: str,
device_id: str = "",
) -> TokenResponse:
token = create_access_token({"sub": str(user.id), "role": user.role})
_set_auth_cookie(response, token)
issued = issue_access_token({"sub": str(user.id), "role": user.role})
set_session_cookie(response, issued.token, issued.expires_at)
detail = f"method={method}"
if device_id:
@@ -112,7 +96,7 @@ def _issue_session(
db.commit()
return TokenResponse(
access_token=token,
access_token=issued.token,
role=user.role,
username=user.username,
permissions=get_user_permissions(user),
@@ -252,7 +236,7 @@ def logout(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
response.delete_cookie(key="access_token", path="/")
clear_session_cookie(response)
db.add(
AuditLog(
user_id=current_user.id,