Django Rest Framework之权限

基本代码结构

  url.py:python

from django.conf.urls import url, include
from app import views
  
urlpatterns = [
    url(r'^test/', views.TestView.as_view()),
]

   views.py:web

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework import exceptions
 
 
class MyPermission(object):
    def has_permission(request, self):
    '''
    权限代码编写区域
    '''
    return True  #权限经过 若是权限不经过 返回False 
 
 
class TestView(APIView):
    permission_classes = [MyPermission, ] 
 
    def get(self, request, *args, **kwargs):
        pass
 
     
     def post(self, request, *args, **kwargs):
        pass
 
        '''
        等等一系列的视图功能方法
        '''

  说明:

    • has_permission方法的返回值是布尔类型,True表示权限经过,False表示权限拒绝
    • 上面的基本结构是作局部的类的权限判断方式,全局权限判断后文介绍。
    • permission_classes属性变量一样也是一个列表,列表元素是权限判断类。

源码分析

  其实权限的源码流程跟认证的流程基本相同。仍是要抓住经过源码要想知道什么,否则就会陷入浩如烟海的源码之中。django

  • 为何会使用permission_classes属性变量?

    

  python 的面向对象编程中,咱们首先要执行的方法确定是dispatch方法,因此咱们的分析入口就是dispatch方法,在dispatch方法中,能够看到,经过initialize_request方法将django原生的request进行了一次封装。由initialize_request方法的实现过程能够看出,将其封装实例化成了一个Request对象。但权限判断并无像认证同样初始化到了Request对象中,但对django原生的request封装仍是须要强调的,由于编写代码的过程当中对django原生的request的使用是必不可免的。编程

    

    一样的,权限判断的具体过程跟认证同样,也是在dispatch方法中所调用的initial方法中实现。再跳转到initial方法中去。api

    

    在initial方法中,能够看到权限判断的方法,没错,就是经过check_permissions方法实现的。再跳转到这个方法中去。app

    

      在check_permissions方法中,就能够看到权限的判断就是经过这个for循环实现的。正由于在业务代码中可能存在若干种类型的权限判断,因此才会经过循环去执行咱们定义好的权限判断类来完成多个权限体系的判断功能。这样,咱们能够感受到这里的“self.get_permissions()”的返回值应该就是咱们在视图类中赋值过的permissions_classes属性变量的值。那就跳转到这个方法中去看看吧。ide

  

  在get_permissions方法中看到,跟认证同样,返回值一样是一个列表生成式,而这个列表生成式使用的属性变量正是咱们赋值过的permission_classes,跟咱们以前的猜想彻底一致。综上所述,咱们为了让drf接口源码使用上咱们本身定义的权限判断类,那咱们就必须按照源码中写的借口,将permission_classes属性变量赋值源码分析

  • 在权限判断类中为何会定义一个名称为has_permission的方法?

  

  回到check_permissions方法中,咱们看if判断句,前面刚刚说过,在for中的permission其实就是咱们本身定义的权限判断类,那么在if句中的“.has_permission(request,self)”不就应该就是Mypermission类中的方法吗?因此,咱们本身定义的Mypermission类中必定要实现has_permission这个方法。(要注意这个方法的参数)    post

  • has_permission方法中,为何返回值为布尔值?

  仍是跟上一个问题同样的,在上图中的if句中,咱们能够看到“permission.has_permission(request, self)”的返回值不就是布尔值吗,这个返回值不就是has_permission方法返回值吗?当返回值为False时,就会执行if句中的代码,来抛出异常。url

  

实例

from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r'^test/', TestView.as_view()),
]
urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission

from rest_framework.request import Request
from rest_framework import exceptions

token_list = [
    'sfsfss123kuf3j123',
    'asijnfowerkkf9812',
]


class TestAuthentication(BaseAuthentication):
    def authenticate(self, request):
        """
        用户认证,若是验证成功后返回元组: (用户,用户Token)
        :param request: 
        :return: 
            None,表示跳过该验证;
                若是跳过了全部认证,默认用户和Token和使用配置文件进行设置
                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()# 默认值为:None
                else:
                    self.auth = None
            (user,token)表示验证经过并设置用户名和Token;
            AuthenticationFailed异常
        """
        val = request.query_params.get('token')
        if val not in token_list:
            raise exceptions.AuthenticationFailed("用户认证失败")

        return ('登陆用户', '用户token')

    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 TestPermission(BasePermission):
    message = "权限验证失败"

    def has_permission(self, request, view):
        """
        判断是否有权限访问当前请求
        Return `True` if permission is granted, `False` otherwise.
        :param request: 
        :param view: 
        :return: True有权限;False无权限
        """
        if request.user == "管理员":
            return True

    # GenericAPIView中get_object时调用
    def has_object_permission(self, request, view, obj):
        """
        视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证
        Return `True` if permission is granted, `False` otherwise.
        :param request: 
        :param view: 
        :param obj: 
        :return: True有权限;False无权限
        """
        if request.user == "管理员":
            return True


class TestView(APIView):
    # 认证的动做是由request.user触发
    authentication_classes = [TestAuthentication, ]

    # 权限
    # 循环执行全部的权限
    permission_classes = [TestPermission, ]

    def get(self, request, *args, **kwargs):
        # self.dispatch
        print(request.user)
        print(request.auth)
        return Response('GET请求,响应内容')

    def post(self, request, *args, **kwargs):
        return Response('POST请求,响应内容')

    def put(self, request, *args, **kwargs):
        return Response('PUT请求,响应内容')
views.py

扩展:全局权限

  一样,跟全局认证同样,咱们只须要在settings配置文件中添加配置项便可。而后,咱们仍然须要将咱们自定义的权限类也写到咱们在跟views.py同级目录下新建的文件夹(我习惯叫utils)中的权限判断文件(permision.py)中去。

  

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES" :['api.utils.permission.Mypermission',]    
}

   Mypermission就是咱们写在utils文件夹中permission.py文件中的一个权限类。

  注意:若是有部分类不须要权限判断的话,能够在Mypermission类中添加“permission_classes = []”,便可。 

相关文章
相关标签/搜索