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

Django Web应用如何基于已实现的登录API适配@login_required装饰器

你的思路是完全符合该场景的规范实现方式,核心逻辑就是复用Knox自带的Token校验能力,把校验通过的用户注入到请求对象中,让Django原生的@login_required装饰器可以识别登录状态,具体实现步骤如下:

实现步骤

1. 新增Token校验中间件(全局校验推荐)

中间件会在每个请求进入视图前自动校验Cookie中的Token有效性,校验通过则自动绑定登录用户到请求对象,无需修改现有视图代码即可适配原生@login_required装饰器。

# app/middleware.py
from django.contrib.auth.models import AnonymousUser
from knox.auth import TokenAuthentication
from django.urls import reverse

class TokenAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.token_auth = TokenAuthentication()

    def __call__(self, request):
        # 配置不需要校验的豁免路径,避免登录页死循环、API重复校验
        exempt_paths = [
            reverse('login_page'), # 替换为你登录页的URL名称
            reverse('register_page'), # 替换为你注册页的URL名称
            '/api/', # DRF接口走自带的认证逻辑,无需中间件处理
            '/static/', # 静态资源跳过校验
        ]
        if any(request.path.startswith(path) for path in exempt_paths):
            return self.get_response(request)
        
        # 从Cookie读取Token
        token = request.COOKIES.get('auth_token')
        if token:
            try:
                # 复用Knox官方校验逻辑,避免自己实现校验的安全漏洞
                user, _ = self.token_auth.authenticate_credentials(token.encode())
                request.user = user
            except Exception:
                request.user = AnonymousUser()
        
        return self.get_response(request)

2. 注册中间件到配置文件

将上面的中间件添加到settings.py的MIDDLEWARE列表,注意必须放在Django自带的认证中间件之后:

# settings.py
MIDDLEWARE = [
    # 其他默认中间件
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    # 新增你的自定义中间件,替换为实际的App名称
    'your_app_name.middleware.TokenAuthMiddleware',
    # 其他中间件
]

3. 修改登录接口,把Token写入Cookie

修改现有LoginAPI的返回逻辑,在响应中自动写入带安全属性的Cookie:

class LoginAPI(KnoxLoginView):
    serializer_class = AuthTokenSerializer
    permission_classes = (permissions.AllowAny,)
    http_method_names = ['post']

    def post(self, request, format=None):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        response = super(LoginAPI, self).post(request, format=None)
        # 从返回结果中获取Knox生成的Token
        token = response.data['token']
        # 写入Cookie,配置安全参数
        response.set_cookie(
            'auth_token',
            token,
            httponly=True, # 禁止JS读取,防范XSS攻击
            secure=request.is_secure(), # HTTPS环境下才会传输Token,生产环境建议强制开启
            samesite='Lax', # 防范CSRF攻击
            max_age=3600 * 24 * 7, # 有效期和Knox Token默认有效期保持一致即可
            path='/'
        )
        return response

4. 修改登出接口,清除Cookie

用户登出时同步删除浏览器端的Token Cookie:

class LogoutAPI(KnoxLogoutView):
    http_method_names = ['post']

    def post(self, request, format=None):
        response = super().post(request, format=None)
        response.delete_cookie('auth_token')
        return response

可选方案:自定义装饰器(仅部分视图需要鉴权时使用)

如果只有少量视图需要做登录校验,不想加全局中间件,可以自定义装饰器替换原生@login_required:

# app/decorators.py
from django.shortcuts import redirect
from knox.auth import TokenAuthentication

def token_login_required(view_func):
    def wrapper(request, *args, **kwargs):
        token = request.COOKIES.get('auth_token')
        if token:
            try:
                user, _ = TokenAuthentication().authenticate_credentials(token.encode())
                request.user = user
                return view_func(request, *args, **kwargs)
            except:
                pass
        # 校验失败跳转到登录页
        return redirect('/login/')
    return wrapper

使用时直接替换原生装饰器即可:

@token_login_required
def user_center(request):
    # 你的视图逻辑
    pass

规范建议

  • 生产环境必须开启HTTPS,确保secure参数生效,避免Token被明文窃取
  • 不要将Token存在LocalStorage中,相比Cookie开启HttpOnly的方案,LocalStorage更容易被XSS攻击盗取Token
  • Knox的Token过期后会自动校验失败,中间件会自动把用户设为匿名状态,@login_required会自动跳转到登录页,无需额外处理过期逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 02:06:06