You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

django-allauth无头模式下X-Session-Token有效但request.user未认证

问题分析与解决

核心问题在于:django-allauth无头模式的SessionTokenMiddleware默认仅处理/_allauth/前缀的请求,你的自定义API路径不在其处理范围内,导致即使正确传入X-Session-Token,request.user也无法被自动填充。而ninja.security.django_auth依赖Django默认的Session Cookie认证机制,和allauth无头的Token认证逻辑不兼容,因此会返回权限拒绝。

解决方案一:让allauth中间件覆盖自定义API路径

在项目settings.py中添加ALLAUTH_HEADLESS配置,将你的API路径纳入中间件处理范围:

ALLAUTH_HEADLESS = {
    "SESSION_TOKEN_MIDDLEWARE_URLS": [
        r"^/_allauth/",
        r"^/api/",  # 新增API路径匹配规则
    ],
}

同时确保allauth.headless.middleware.SessionTokenMiddleware已正确加入MIDDLEWARE列表,且顺序符合要求(在SessionMiddleware之后、AuthenticationMiddleware之前):

MIDDLEWARE = [
    # ... 其他中间件
    "django.contrib.sessions.middleware.SessionMiddleware",
    "allauth.headless.middleware.SessionTokenMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    # ... 其他中间件
]

配置完成后,allauth中间件会自动处理/api/开头的请求,通过X-Session-Token完成认证并填充request.user,此时使用ninja.security.django_auth即可正常生效。

解决方案二:自定义Ninja认证类(灵活适配)

若不想让allauth中间件处理所有API请求,可自定义适配allauth Session Token的Ninja认证类:

  1. 创建security.py文件编写认证逻辑:
from ninja.security import HttpBearer
from allauth.headless.internal.session import get_session_from_token
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser

User = get_user_model()

class AllAuthSessionTokenAuth(HttpBearer):
    def authenticate(self, request, token):
        # 通过Token获取对应Session
        session = get_session_from_token(token)
        if not session:
            return AnonymousUser()
        
        # 从Session中提取用户ID并返回用户实例
        user_id = session.get("_auth_user_id")
        if user_id:
            try:
                return User.objects.get(pk=user_id)
            except User.DoesNotExist:
                pass
        return AnonymousUser()
  1. 在Ninja API或路由中使用该认证类:
# api.py
from ninja import NinjaAPI
from .security import AllAuthSessionTokenAuth

api = NinjaAPI(auth=AllAuthSessionTokenAuth())
api.add_router("website/", "website.api.router")

或针对单个路由配置:

# website.api.py
from ninja import Router
from .security import AllAuthSessionTokenAuth
# ... 其他导入

router = Router(auth=AllAuthSessionTokenAuth())

@router.get("/blog_category", response=List[BlogCategoryRetrieveSchema])
async def blog_category_retrieve(request):
    print(request.user)  # 此时会输出已认证的用户实例
    # ... 业务逻辑

两种方案均可解决问题:方案一更简洁,适合全API需要allauth认证的场景;方案二更灵活,可针对特定路由或API配置认证规则。

内容的提问来源于stack exchange,提问作者Coding Guy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 13:31:17