Отзыв JWT при выходе и смене пароля
logout отзывает предъявленный токен по jti (in-memory denylist до exp); смена и сброс пароля инкрементят users.token_version (claim ver в JWT, сверка в auth/deps) — все прежние сессии отзываются. Своё устройство при смене пароля остаётся в сессии (перевыдача cookie). Миграция 0013. #57 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
This commit is contained in:
@@ -41,7 +41,7 @@ def admin_login(
|
||||
session: Session = Depends(get_session),
|
||||
) -> s.AdminMe:
|
||||
admin = admin_service.authenticate_admin(session, body.username, body.password)
|
||||
security.set_admin_session(response, admin.id) # type: ignore[arg-type]
|
||||
security.set_admin_session(response, admin.id, admin.token_version) # type: ignore[arg-type]
|
||||
audit_service.record(
|
||||
session,
|
||||
actor_id=admin.id,
|
||||
@@ -56,7 +56,8 @@ def admin_login(
|
||||
|
||||
|
||||
@router.post("/auth/logout", response_model=s.OkResponse)
|
||||
def admin_logout(response: Response) -> s.OkResponse:
|
||||
def admin_logout(request: Request, response: Response) -> s.OkResponse:
|
||||
security.revoke_session_token(request, security.ADMIN_COOKIE, security.AUDIENCE_ADMIN)
|
||||
security.clear_admin_session(response)
|
||||
return s.OkResponse()
|
||||
|
||||
|
||||
@@ -116,6 +116,9 @@ def telegram_register(
|
||||
|
||||
|
||||
@router.post("/logout", response_model=s.OkResponse)
|
||||
def logout(response: Response) -> s.OkResponse:
|
||||
def logout(request: Request, response: Response) -> s.OkResponse:
|
||||
# Отзываем именно предъявленный токен (по jti) до его exp: украденная/оставленная
|
||||
# cookie перестаёт работать сразу, а не живёт до конца TTL (#57).
|
||||
security.revoke_session_token(request, security.USER_COOKIE, security.AUDIENCE_USER)
|
||||
security.clear_user_session(response)
|
||||
return s.OkResponse()
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"""Роутер текущего пользователя."""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Query, Request, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, Query, Request, Response, UploadFile
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlmodel import Session
|
||||
|
||||
from app.auth.deps import get_current_user
|
||||
from app.auth.password import check_current_password
|
||||
from app.auth.telegram import TelegramProvider
|
||||
from app.core.security import client_ip
|
||||
from app.core.security import client_ip, set_user_session
|
||||
from app.core.errors import NotFoundError
|
||||
from app.db.session import get_session
|
||||
from app.models import User
|
||||
@@ -122,6 +122,7 @@ def update_my_profile(
|
||||
def change_my_password(
|
||||
body: s.PasswordChange,
|
||||
request: Request,
|
||||
response: Response,
|
||||
session: Session = Depends(get_session),
|
||||
user: User = Depends(get_current_user),
|
||||
) -> s.MeRead:
|
||||
@@ -130,6 +131,9 @@ def change_my_password(
|
||||
if had_password:
|
||||
check_current_password(user, body.current_password)
|
||||
user_service.set_password(session, user, body.new_password)
|
||||
# set_password инкрементит token_version → все ранее выданные токены отозваны (#57).
|
||||
# Перевыдаём cookie этому устройству со свежим ver, чтобы разлогинить только остальные.
|
||||
set_user_session(response, user.id, user.auth_provider, user.token_version)
|
||||
audit_service.record(
|
||||
session,
|
||||
actor_id=user.id,
|
||||
|
||||
Reference in New Issue
Block a user