zoukankan      html  css  js  c++  java
  • 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 = []
  • 相关阅读:
    Android 中向本地保存图片的时候,不在图库显示
    shopfiy 二次开发之自定义 sections
    shopfiy 二次开发之条件判断
    Linux中为RabbitMQ调整文件句柄数和socket连接数
    python helium 安装使用
    python log 打印
    linux 查看服务器登录失败的ip和次数
    在阿里云WINDOWS机器上部署的JAVA SpringBoot 时不时的无效 。
    打开TLS 1.1和1.2而不影响其他协议
    美团供应链架构演进
  • 原文地址:https://www.cnblogs.com/midworld/p/11075977.html
Copyright © 2011-2022 走看看