"""项目自定义认证后端 SimpleJWT 的 JWTAuthentication 在 __init__ 中调用 django.contrib.auth.get_user_model(), 返回 AUTH_USER_MODEL 指定的模型(未配置时为 Django 默认 auth.User)。 本项目使用 gvsds.apps.core.models.User 作为用户模型(未设置 AUTH_USER_MODEL), 因此需要覆盖 user_model,使 JWT 认证查询正确的用户表。 同时支持从 Authorization 请求头和 HttpOnly Cookie 读取 JWT, 以兼容前端基于 Cookie 的认证方式(credentials: 'include')。 额外职责:JWT 认证成功后立即解析当前角色上下文(ResolveRoleContext, 唯一实现位于 gvsdsdk.auth.middleware,与 CurrentRoleMiddleware 共用)。 这解决了 Django 中间件在 DRF 认证之前运行、 导致中间件无法获取已认证用户的问题。 """ from rest_framework_simplejwt.authentication import JWTAuthentication from gvsds.apps.core.models import User from gvsdsdk.auth.middleware import ResolveRoleContext #: 存储 Access Token 的 Cookie 名称 JWT_ACCESS_COOKIE = 'AccessToken' #: 存储 Refresh Token 的 Cookie 名称 JWT_REFRESH_COOKIE = 'RefreshToken' class CustomJWTAuthentication(JWTAuthentication): """JWT 认证——使用项目自定义 User 模型(core.User) 优先从 Authorization 请求头读取 token; 若请求头无 token,则回退到 HttpOnly Cookie(AccessToken)。 认证成功后立即解析当前角色上下文(ResolveRoleContext), 确保 request.current_role / current_company_uuid / current_tenant_uuid 可用。 """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.user_model = User def get_header(self, request): """优先从 Authorization 头获取,回退到 Cookie""" header = super().get_header(request) if header is not None: return header # 回退:从 Cookie 读取 access token,构造标准 Bearer 头 cookie_token = request.COOKIES.get(JWT_ACCESS_COOKIE) if cookie_token: auth_header_types = self.get_auth_header_types() prefix = f'{auth_header_types[0]} '.encode('utf-8') if auth_header_types else b'' return prefix + cookie_token.encode('utf-8') return None def get_auth_header_types(self): from rest_framework_simplejwt.settings import api_settings return api_settings.AUTH_HEADER_TYPES def authenticate(self, request): """JWT 认证成功后立即解析角色上下文""" result = super().authenticate(request) if result is None: return None user, validated_token = result # 认证成功后立即解析角色上下文(DRF 会在 authenticate 返回后设置 request.user, # 但此时我们已有 user 实例,可直接传入解析) ResolveRoleContext(request, user) return result