rest framework 权限

一、权限示例

需求:不同的用户类型有不同的权限

  • 普通用户:只能查看个人信息相关,序号:1
  • VIP 用户:只能查看个人信息相关,序号:2
  • SVIP 用户:查看订单相关信息,序号:3

1、新建 app/utils/permission.py

class SVIPPermission(object):
    def has_permission(self, request, view):
        """是否有权限"""
        if request.user.user_type != 3:
            return False
        return True
    
    
class MyPermission(object):
    """普通、VIP 用户"""
    def has_permission(self, request, view):
        """是否有权限"""
        if request.user.user_type == 3:
            return False
        return True

如果用户类型为 3 即 SVIP,那么就返回 True,否则返回 False。

Note:只有登录后的用户才有 request.user,即在用户认证的时候,返回用户对象

2、views.py

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.authentication import BasicAuthentication
import hashlib
import time
from app import models
from django.http import JsonResponse
from .utils.auth import MyAuthentication
from .utils.permission import SVIPPermission


class OrderView(APIView):
    """订单管理"""
    # authentication_classes = [MyAuthentication, ]  # 添加认证(因为已经全局设置了认证,所有就不单独设置了)

    permission_classes = [SVIPPermission, ]		# 权限

    def get(self, request, *args, **kwargs):
        ret = {'code': 1000, 'msg': None, 'data': None, }
        ret['data'] = ORDER_DICT
        print(request.user)
        return JsonResponse(ret)
    
    
class UserInfo(APIView):
    """用户个人信息"""
    permission_classes = [MyPermission, ]

    def get(self, request, *args, **kwargs):
        user_name = request.user.username
        return HttpResponse(user_name)

3、现在带上 token(表示已经登录),查看订单:

SVIP 用户:

4、查看用户个人信息:(rose:普通用户)

5、project/urls.py

为了遵循 RESTful API 规范,现在将 URL 修改为如下:

from django.contrib import admin
from django.urls import path
from app.views import IndexView, OrderView, UserInfo

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/index/', IndexView.as_view()),
    path('api/v1/order/', OrderView.as_view()),
    path('api/v1/info/', UserInfo.as_view())
    
]

二、全局配置

与认证一样,权限也可以全局配置和局部配置,全局配置可以使得所有的视图类生效,需要在 settings 中配置:

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ['app.utils.auth.MyAuthentication', ],
    "UNAUTHENTICATED_USER": lambda: '匿名用户',
    "UNAUTHENTICATED_TOKEN": None,
    "DEFAULT_PERMISSION_CLASSES": ['app.utils.permission.SVIPPermission'],		# 这句

}

如果想配置没有访问权限返回的信息,可以修改 app/utils/permission.py

class SVIPPermission(object):
    message = '必须 SVIP 才能访问!'		# 这句
    def has_permission(self, request, view):
        """是否有权限"""
        if request.user.user_type != 3:
            return False
        return True

三、内置权限

rest framework 也有内置的权限 rest_framework/permissions.py

@six.add_metaclass(BasePermissionMetaclass)
class BasePermission(object):
    """
    A base class from which all permission classes should inherit.
    """

    def has_permission(self, request, view):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

自定义的权限类,最好要继承 BasePermission

# app/utils/permisiion.py
from rest_framework.permissions import BasePermission


class SVIPPermission(BasePermission):
    message = '必须 SVIP 才能访问!'
    def has_permission(self, request, view):
        """是否有权限"""
        if request.user.user_type != 3:
            return False
        return True

四、权限认证流程(源码)

1、请求过来先执行 dispatch() 方法,dispatch() 方法中 initial() 初始化请求相关信息:

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)

2、check_permissions()

 def check_permissions(self, request):
     """
     Check if the request should be permitted.
     Raises an appropriate exception if the request is not permitted.(检查是否应该允许请求。
      如果不允许请求,则引发适当的异常)
     """
     # 权限列表,self.get_permissions() = MyPermission(),调用其中的 has_permission() 方法
     for permission in self.get_permissions():
         if not permission.has_permission(request, self):
             self.permission_denied(
                request, message=getattr(permission, 'message', None)
             )

从上面可以看到其实权限认证,主要是调用 has_permission() 方法,若我们自定义权限类,只需实现这个方法即可。

self.get_permissions() 其本质是在定义权限类对象列表:[MyPermission(), ],具体可见 3

  • has_permission() 返回 True,即有权限访问,则不执行 self.permission_denied()
  • 若访问 False,即无权访问,则执行 self.permission_denied(),在其中返回的错误信息就是 message 所定义的,因此我们也可以自定义 message 的内容。

3、get_permissions()

def get_permissions(self):
    """
    Instantiates and returns the list of permissions that this view requires.
    实例化并返回此视图所需的权限列表。
    """
     # permission_classes = [MyPermission, ],返回对象列表
    return [permission() for permission in self.permission_classes]


源码流程图

总结

  • 自定权限类,需继承 BasePermission
  • 类中必须实现 has_permission() 方法
  • 全局定义权限(可设置 settings),局部视图类不设置权限认证,可设置 permission_classes = []
原文地址:https://www.cnblogs.com/midworld/p/11075977.html