Files
medical_training/apps/user/auth/logout.py
T

52 lines
1.7 KiB
Python

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework import serializers as drf_serializers
from rest_framework_simplejwt.tokens import RefreshToken
from drf_spectacular.utils import extend_schema, inline_serializer
from apps.user.utils.jwt_redis import revoke_token
from apps.user.audit import log_logout
@extend_schema(
summary='U7 退出登录',
request=inline_serializer('LogoutRequest', fields={
'refresh': drf_serializers.CharField(help_text='refresh token'),
}),
responses={200: inline_serializer('LogoutResponse', fields={
'message': drf_serializers.CharField(),
})},
tags=['认证'],
)
@api_view(['POST'])
@permission_classes([AllowAny])
def logout(request):
"""U7 退出登录 — 无论 token 是否合法均返回 200(防探测)"""
refresh_raw = request.data.get('refresh', '')
jti = None
user_id = None
if refresh_raw:
try:
token = RefreshToken(refresh_raw)
jti = token.payload.get('jti')
exp = token.payload.get('exp')
user_id = token.payload.get('user_id')
if jti and exp:
revoke_token(jti, exp)
except Exception:
pass # 静默处理无效 token
# 审计:优先取已认证用户,兜底取 token payload
audit_uid = None
if hasattr(request, 'user') and request.user and request.user.is_authenticated:
audit_uid = request.user.id
elif user_id:
audit_uid = user_id
if audit_uid:
log_logout(audit_uid, jti=jti)
return Response({'message': '已退出登录'})