基于Django生态的微服务认证系统正确性验证及中间件优化问询
认证逻辑正确性确认与TokenAuthenticationMiddleware配置方案
一、当前认证逻辑的正确性确认
你的认证流程整体符合Django生态下的标准安全实践,细节上需注意以下几点:
- 登录校验环节:在
UserLoginSerializer中同时校验账号密码与Django Axes锁定状态是合理的——Axes的核心作用就是拦截多次登录失败请求,提前在序列化器层面校验能避免后续不必要的Token生成操作,符合安全逻辑。 - Token生成与登录时间更新:使用Django OAuth Toolkit生成Token、调用
update_last_login更新用户登录时间是标准操作,只要确保调用OTK的Token生成方法(如AccessToken.objects.create_token(user=user))正确,这部分无问题。 - 客户端Token存储:将Token存入Session可行,但需确保后续客户端发起请求时,能以中间件可识别的方式传递Token(比如放在
Authorization头的Bearer字段,或自定义Cookie),否则中间件无法完成校验。 - 登出流程:使Token过期(可通过OTK的
AccessToken.objects.revoke(token)或设置过期时间)+ 发送登出信号(如Django内置的user_logged_out)是正确的,能有效终止Token有效性并触发后续清理动作。
二、配置TokenAuthenticationMiddleware仅作用于带@login_required的视图
Django中间件默认全局执行,要实现仅对特定视图校验,可通过修改中间件的process_view方法实现,具体方案如下:
1. 中间件核心逻辑修改
在你的TokenAuthenticationMiddleware中添加视图过滤逻辑:
from django.contrib.auth.decorators import login_required import inspect from django.urls import resolve from django.http import HttpResponseRedirect class TokenAuthenticationMiddleware: def __init__(self, get_response): self.get_response = get_response # 定义需要排除的公开视图名称(根据实际视图name填写) self.EXEMPT_VIEWS = [ 'login', 'password_reset', 'password_reset_done', 'password_reset_confirm', 'password_reset_complete' ] def __call__(self, request): response = self.get_response(request) return response def extract_token(self, request): # 实现从请求中提取Token的逻辑,比如从Authorization头或Cookie获取 auth_header = request.META.get('HTTP_AUTHORIZATION', '') if auth_header.startswith('Bearer '): return auth_header.split(' ')[1] return request.COOKIES.get('auth_token') def validate_token(self, token): # 实现Token有效性校验逻辑,调用OTK的验证方法 from oauth2_provider.models import AccessToken try: access_token = AccessToken.objects.get(token=token) return not access_token.is_expired() except AccessToken.DoesNotExist: return False def get_user_from_token(self, token): # 从有效Token中获取用户 from oauth2_provider.models import AccessToken return AccessToken.objects.get(token=token).user def process_view(self, request, view_func, view_args, view_kwargs): # 先判断当前视图是否在排除列表中 resolved_url = resolve(request.path_info) if resolved_url.url_name in self.EXEMPT_VIEWS: return None # 跳过校验 # 判断视图是否被@login_required装饰 view_func_actual = getattr(view_func, '_wrapped', view_func) has_login_required = False for decorator in inspect.getclosurevars(view_func_actual).nonlocals.values(): if isinstance(decorator, login_required): has_login_required = True break # 仅对带@login_required的视图执行Token校验 if has_login_required: token = self.extract_token(request) if not token or not self.validate_token(token): # 返回未认证响应,可根据需求调整为401或重定向 return HttpResponseRedirect('/login/') # 绑定用户到request.user request.user = self.get_user_from_token(token) return None
2. 针对DRF API视图的补充处理
如果系统包含DRF API视图,通常用permission_classes = [IsAuthenticated]代替@login_required,可在process_view中补充判断:
from rest_framework.permissions import IsAuthenticated # 在has_login_required判断后添加: if not has_login_required: # 检查DRF视图的权限配置 if hasattr(view_func, 'cls'): drf_view_cls = view_func.cls if IsAuthenticated in getattr(drf_view_cls, 'permission_classes', []): has_login_required = True
3. 中间件顺序配置
确保TokenAuthenticationMiddleware在django.contrib.auth.middleware.AuthenticationMiddleware之后,在settings.py的MIDDLEWARE中配置:
MIDDLEWARE = [ # 其他中间件... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'your_app.middleware.TokenAuthenticationMiddleware', # 其他中间件... ]
内容的提问来源于stack exchange,提问作者user18908978
相关产品推荐
相关产品推荐

