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
相关产品推荐
相关产品推荐

