Django的session和auth应用配合起来很方便的实现了身份认证和会话管理的功能。
现在我的项目在原有网站基础上需要另外提供一套API,只需要简单的一点拓展就可以在现有session和auth应用基础上实现基于Token的认证。
在自己的app下创建middleware.py文件,写一个自己的class,继承django.contrib.session.middleware模块下的SessionMiddleware类,并且重写process_request方法。
1 2 3 4 5 6 7 8 9 10 11 12
| from django.conf import settings from django.contrib.sessions.middleware import SessionMiddleware
class SessionTokenMiddleware(SessionMiddleware):
def process_request(self, request): session_key = request.META.get("HTTP_" + getattr(settings, "ACCESS_TOKEN_NAME", "Access-Token").replace("-","_").upper()) if not session_key: super().process_request(request) else: request.session = self.SessionStore(session_key)
|
在处理请求时,先尝试从请求头中对应字段获取Token,即Session Key,并通过Session引擎获取Session对象。
如果请求头中没有包含Token字段,则调用父类方法。
最后,在登陆API的view中调用auth模块login方法后,从request中获取Session Key放入到响应体中即可。
这里因为是用了 REST-Framework 的 ViewSet,所以需要通过request.stream获取原始Django的HttpRequest对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @list_route(methods=["post"], permission_classes=[permissions.AllowAny]) def login(self, request): """ 登陆API
通过手机号和密码进行登陆验证 """ serializer = UserSerializer(data=request.data) if serializer.authenticate(): login(request, serializer.authenticated_user) response_data = { getattr(settings, "ACCESS_TOKEN_NAME", "Access-Token"): request.stream.session.session_key, "Expires": int((time.time() + request.stream.session.get_expiry_age()) * 1000) } response_data.update(serializer.data) return Response(data=response_data, status=status.HTTP_200_OK) else: logout(request) return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|