源码剖析Django REST framework的认证方式及自定义认证 (2)

然后执行initial方法来处理新得到的request对象,再来看看initial方法中又执行了哪些操作

def initial(self, request, *args, **kwargs): self.format_kwarg = self.get_format_suffix(**kwargs) neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)

由上面的源码可以知道,在initial方法中,执行perform_authentication来对request对象进行认证操作

def perform_authentication(self, request): request.user

perform_authentication方法中调用执行request中的user方法,这里的request是封装了原始request,认证对象列表,处理器列表等之后的request对象

class Request(object): ... @property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes provided to the request. """ if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user

从request中获取_user的值,如果获取到则执行_authenticate方法,否则返回_user

def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ for authenticator in self.authenticators: try: user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple return

在这里self.authenticators实际上是get_authenticators方法执行完成后返回的对象列表

class Request(object): def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): assert isinstance(request, HttpRequest), ( 'The `request` argument must be an instance of ' '`django.http.HttpRequest`, not `{}.{}`.' .format(request.__class__.__module__, request.__class__.__name__) ) self._request = request self.parsers = parsers or () self.authenticators = authenticators or () ...

循环认证的对象列表,执行每一个认证方法的类中的authenticate方法,得到通过认证的用户及用户的口令的元组,并返回元组完成认证的流程

在_authenticate方法中使用了try/except方法来捕获authenticate方法可能出现的异常

如果出现异常,就调用_not_authenticated方法来设置返回元组中的用户及口令并终止程序继续运行

总结,Django restframework的认证流程如下图

源码剖析Django REST framework的认证方式及自定义认证

Django restframework内置的认证类

在上面的项目例子中,在UsersView的get方法中,打印authentication_classes和request._user的值

class UserView(APIView): # authentication_classes = [MyAuthentication,] def get(self,request,*args,**kwargs): print('authentication_classes:', self.authentication_classes) print(request._user) return HttpResponse("UserView GET")

打印结果为

authentication_classes: [<class 'rest_framework.authentication.SessionAuthentication'>, <class 'rest_framework.authentication.BasicAuthentication'>] AnonymousUser

由此可以知道,authentication_classes默认是Django restframework内置的认证类,而request._user为AnonymousUser,因为发送GET请求,用户没有进行登录认证,所以为匿名用户

在视图函数中导入这两个类,再查看这两个类的源码,可以知道

class BasicAuthentication(BaseAuthentication): www_authenticate_realm = 'api' def authenticate(self, request): ... def authenticate_credentials(self, userid, password): ... class SessionAuthentication(BaseAuthentication): def authenticate(self, request): ... def enforce_csrf(self, request): ... class TokenAuthentication(BaseAuthentication): ...

从上面的源码可以发现,这个文件中不仅定义了SessionAuthentication和BasicAuthentication这两个类,

相关的类还有TokenAuthentication,而且这三个认证相关的类都是继承自BaseAuthentication类

从上面的源码可以大概知道,这三个继承自BaseAuthentication的类是Django restframework内置的认证方式.

自定义认证功能

在上面我们知道,Request会调用认证相关的类及方法,APIView会设置认证相关的类及方法

所以如果想自定义认证功能,只需要重写authenticate方法及authentication_classes的对象列表即可

修改上面的例子的views.py文件

from django.shortcuts import render, HttpResponse from rest_framework.views import APIView from rest_framework.authentication import BaseAuthentication from rest_framework import exceptions TOKEN_LIST = [ # 定义token_list 'aabbcc', 'ddeeff', ] class UserAuthView(BaseAuthentication): def authenticate(self, request): tk = request._request.GET.get("tk") # request._request为原生的request if tk in TOKEN_LIST: return (tk, None) # 返回一个元组 raise exceptions.AuthenticationFailed("用户认证失败") def authenticate_header(self, request): # 如果不定义authenticate_header方法会抛出异常 pass class UserView(APIView): authentication_classes = [UserAuthView, ] def get(self, request, *args, **kwargs): print(request.user) return HttpResponse("UserView GET")

启动项目,在浏览器中输入:8000/users/?tk=aabbcc,然后回车,在服务端后台会打印

aabbcc

把浏览器中的url换为:8000/users/?tk=ddeeff,后台打印信息则变为

ddeeff

这样就实现REST framework的自定义认证功能

Django restframework认证的扩展 基于Token进行用户认证

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwssg.html