52 lines
1.7 KiB
Python
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': '已退出登录'})
|