首先得有一点常识,比如用户认证,就是authenticate

比如一个函数,应该有返回值,

比如一个类里面的self,真的是代表本身这个类吗

再比如看到一个东西加括号,就两种情况,一种是函数,一种是类,区分函数和类,就看加括号之后的东西,是否还调用属性或者方法

还有如果你用pycharm,看源码就很方便了,看到一个属性或方法,你需要做的就是按住ctrl点进去就行了

假设你已经知道,dispatch函数是源码的入口,然后我们就可以愉快的交流了

下面演示如何使用rest_framework的用户认证功能,以及为什么要这样做

1.写路由匹配

  因为是cbv视图,所以用as_view()  

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/', views.TestView.as_view()),
]

2.CBV风格视图

from django.shortcuts import HttpResponse

from rest_framework.views import APIView#导入rest_framework的试图类

class TestView(APIView):
  self.dispatch      #只是为了进源码
def get(self,request,*args,**kwargs):
return HttpResponse('ok')

好了,最基本的框架就这样搭好了,我们开始看源码,源码的入口是在   APIView 的dispatch方法,所以我们点进去

dispatch函数:

    def dispatch(self, request, *args, **kwargs):#这是APIView类的入口
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
和Django的dispatch类似,但是增加了额外的钩子,比如开始,结束,以及异常的处理
"""
self.args = args #封装参数
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs) #重新封装了request
self.request = request
self.headers = self.default_response_headers # deprecate? try:
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response

经过观察,这个函数里面,能让我们感觉有东西的地方就是重新封装request和self.initial初识化这两个地方

1.1先看重新封装request这个

    def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
返回初始化后的request
"""
parser_context = self.get_parser_context(request) return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(), #重点关注这个,看名字就应该找到这个,继续点进去
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)

1.2

def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes] #从配置读取用户认证配置,然后实例化,点进这个self.authentication_classes

这个函数返回了一个列表,通过列表生成式,循环    self.authentication_classes   ,然后拿到的东西实例化

tips:看到一个东西加括号,就两种情况,一种是函数,一种是类,区分函数和类,就看加括号之后的东西,是否还调用属性或者方法

1.3

class APIView(View):

    # The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES      #
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES

坏了,这下不能点了,看settings,说明这是配置信息,好了,看request看到这就走不下去了,因为不能点了,现在我们拿到的信息是:

  在封装request的时候, 把一个auth()列表传到了request的参数里面,然后这个auth()是从这个self.authentication_classes 里面拿到的

现在我们可以打印一下这个  self.authentication_classes,self就是APIview 嘛,我门的视图函数就是继承了这个类啊,所以,打印一下:

拿到了这个:

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

这种情况应该兴奋,因为真的有东西,拿到的是个路径,然后我们就可以用这个路径拿到这两个类

并且,验证了self.authentication_classes  就是个列表,然后里面是一个一个类

如果我们自己写这个authentication_classes的话,也要写成一个列表,里面是一个个类,下面看一下这个类要怎么写

1.4

然后我们先导入一下这个路径,看一下里面写的啥,

from rest_framework.authentication import SessionAuthentication

点进去

是一个新的文件

总体看一下,这个文件有这样几个类

然后都继承了BaseAuthentication类,先看一下这个类

1.5

class BaseAuthentication(object):
"""
All authentication classes should extend BaseAuthentication.
""" def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.") def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass

没有什么实质性的东西,但是规定了继承这个类的子类,必须要有这个   authenticate   方法,否则就会报错,所以我们就知道了应该怎么自己写这个类了

那就可以猜到,下面继承了这个基类的几个子类就是不同的认证方法了

看了这个基类,大概知道自己定义的类里面必须要写这样一个authenticate   方法,不写会报错,但是应该怎么写呢?需要返回什么呢,其实重点是要返回什么

我们现在才走了一半,只看了封装request这一部分,还有初始化呢,重新点进dispatch函数,找到

2.1

    def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use. version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
#用户认证
self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)

我们雄厚的英文实力告诉我们,这个东西是我们要的       self.perform_authentication(request)      -------执行认证

注意这里传了参数,是封装后的request

2.2

    def perform_authentication(self, request):
"""
Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user

就执行了一个request.user,这个user应该是个方法,才能直接这么用,所以再找request里面的user方法,

2.3

    @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'):
self._authenticate()
return self._user

果不其然,是一个加了装饰器的方法,我们的request里面没有这个_user属性,所以执行的是   self._authenticate()  这个方法

2.4

    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._not_authenticated()

循环   self.authenticators,拿到   authenticator 并执行 authenticator 里面的  authenticate 方法,参数为request

注意, self.authenticators  这个东西在1.1中就已经拿到了,这个就是我们要写的验证的类,然后跟我们得到的结论也一样,有一个authentic 方法

2.5 看看这个方法,authentic

    def authenticate(self, request):
return (self.force_user, self.force_token)

哦,返回一个元组,大概就是  用户和token,现在这两行代码是如果有指定值的时候的情况,但是可以说明问题

再看看1.4里面那几个验证的子类,基本上就确认是返回一个已通过认证的用户和对应的token

这是通过认证的情况

2.6再看2.4里面,最后那个     self._not_authenticated()   ,是表示未通过验证的情况

点进去

    def _not_authenticated(self):
"""
Set authenticator, user & authtoken representing an unauthenticated request. Defaults are None, AnonymousUser & None.
"""
self._authenticator = None if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None

没有默认值的话,是返回None的,但是是有默认值的

点进去api_settings ,是个类

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

再点进去,就是rest_framework的配置文件

搜一下,就可以看到这条配置

'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
'UNAUTHENTICATED_TOKEN': None,

默认是调用Django的匿名用户类,所以默认如果不登录,是匿名用户

还能说明一个问题,不登录也能访问,即匿名用户访问是否被允许,就可以在认证类中配置了,返回None,就是允许,抛出异常就是不允许

贴一个完整的代码

from django.shortcuts import HttpResponse

from rest_framework.views import APIView#导入rest_framework的试图类

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from . import models
class CustomAuthenticate(BaseAuthentication):
"""
All authentication classes should extend BaseAuthentication.
""" def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
tk = request.query_param.get('tk') #获取用户输入的token 简化写法,就直接在url中传参了
token_obj = models.Token.objects.filter(token=tk).first()
if token_obj:
return (token_obj.user,token_obj) raise exceptions.AuthenticationFailed('请登录') #抛出异常表示不允许匿名用户访问 # else:
# return (None,None)
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
class TestView(APIView):
authentication_classes = [CustomAuthenticate,] #应用认证配置类
def get(self,request,*args,**kwargs):
return HttpResponse('ok')

源码怎么找之rest_framework的用户认证的更多相关文章

  1. javac编译不同目录的源码提示找不到符号

    对于单个文件的且不引用其他类文件的java源码用javac编译大家都很熟悉即 javac mycode.java 但是如果这个文件引用到了其他的类文件,在进行编译的时候就会提示找不到符号,这时我们需要 ...

  2. (转)OpenFire源码学习之七:组(用户群)与花名册(用户好友)

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413651 Group 在openfire中的gorop——组,也可以理解为共享组.什 ...

  3. Android 4.1源码编译找不到资源文件解决办法

    我们在Android framework中修改资源文件时,在Android 4.0之前,都是直接在sourcecode/frameworks/base/core/res/res下面添加对应的资源文件, ...

  4. [Go] gocron源码阅读-判断是否使用root用户执行

    判断是linux系统,并且uid为0,allowRoot是通过命令行传参传进来的,通过flag包解析出来的,可以使用go run node.go -h看到这些参数 && !allowR ...

  5. Rest_framework Router 路由器(含SimplyRouter源码浅解)

    目录 Rest_framework Router 路由器 ViewSet结合Router,自动生成url. 将ViewSet注册到Router中,需要三个要素: 关于路由规则,细分有四类: rest_ ...

  6. v79.01 鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上) | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(用户态锁篇) | 如何使用快锁Futex(上) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...

  7. Django rest framework 源码分析 (1)----认证

    一.基础 django 2.0官方文档 https://docs.djangoproject.com/en/2.0/ 安装 pip3 install djangorestframework 假如我们想 ...

  8. 2014年6月份第1周51Aspx源码发布详情

    企业汽车服务终端管理系统源码  2014-6-3 [VS2010]源码描述:本系统专门服务于(汽车美容4s店) 完整的一套汽车美容管理服务系统. 功能介绍:汽车美容服务终端功能强大而又简便实用,界面友 ...

  9. 【腾讯Bugly干货分享】微信Tinker的一切都在这里,包括源码(一)

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57ecdf2d98250b4631ae034b 最近半年以来,Android热补 ...

随机推荐

  1. RobotFramework自动化测试框架-移动手机自动化测试Click Element At Coordinates关键字的使用

    Click Element At Coordinates关键字通过一个具体的坐标点,来模拟点击一个Element,该关键字接收两个参数[ coordinate_X | coordinate_Y ]. ...

  2. Iframe父子窗口之间的跨域事件调用和传值

    实现方案1:location.hash传值 父页面:parent.html(所在域:www.parent.com) 子页面:child.html(所在域:www.child.com) 要实现父子页面双 ...

  3. win10 uwp 活动磁贴

    本文翻译:https://mobileprogrammerblog.wordpress.com/2015/12/23/live-tiles-and-notifications-in-universal ...

  4. A low-cost wear-leveling algorithm for block-mappingsolid-state disks

    [] Li-Pin Chang,Li-Chun Huang.A low-cost wear-leveling algorithm for block-mapping solid-state disks ...

  5. ajax 轮询 和 php长连接

     只看加粗的字体 js   部分       1:  ajax 成功回调函数中 一定要用时间函数间隔调用  get_comment(). get_comments('init'); function ...

  6. LeetCode 560. Subarray Sum Equals K (子数组之和等于K)

    Given an array of integers and an integer k, you need to find the total number of continuous subarra ...

  7. LeetCode 169. Majority Element (众数)

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  8. Android Studio 3.0 使用问题解决方案总结

    问题:创建新项目非常慢 问题描述: 更新到3.0版本后,出现创建新项目一直停留在如下图的界面: 选择等待?不知道要等到什么时候,这时候怎么办呢?显然,不能一直等待下去呀,需要想办法让他能尽快的加载好才 ...

  9. 关于laravel5.5控制器方法参数依赖注入原理深度解析及问题修复

    在laravel5.5中,可以根据控制器方法的参数类型,自动注入一个实例化对象,极大提升了编程的效率,但是相比较与Java的SpringMVC框架,功能还是有所欠缺,使用起来还是不太方便,主要体现在方 ...

  10. Hive简单安装

    数据库的创建 Hive1版本 在此之前要安装好JDK,HADOOP,下载解压Hive 在root下安装mysql:yum install mysql-server mysql-client //一般M ...