前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django-REST-framework 权限管理源码分析

Django-REST-framework 权限管理源码分析

作者头像
JuneBao
发布2022-10-26 14:31:14
6680
发布2022-10-26 14:31:14
举报
文章被收录于专栏:JuneBao

REST framework 权限管理源码分析

:fa-user: :fa-heart: :fa-user: 同认证一样,dispatch()作为入口,从self.initial(request, *args, **kwargs)进入initial()

代码语言:javascript
复制
    def initial(self, request, *args, **kwargs):
        # .......
        # 用户认证
        self.perform_authentication(request)
        # 权限控制
        self.check_permissions(request)
        # ...

check_permissions()便是权限管理源码的入口

代码语言:javascript
复制
    # 权限管理
    def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

和用户认证一样,同样遍历一个权限类对象列表,并且调用该列表中元素的has_permission()方法,该方法返回布尔值,True代表有权限,False代表没有权限.

代码语言:javascript
复制
    def get_permissions(self):
        return [permission() for permission in self.permission_classes]

如果没有权限,就调用permission_denied()

代码语言:javascript
复制
    def permission_denied(self, request, message=None):
        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated()
        raise exceptions.PermissionDenied(detail=message)

如果使用了REST的认证框架(authentication_classes数组不为空)并且身份认证失败,就抛出NotAuthenticated异常,否则会抛出PermissionDenied异常

代码语言:javascript
复制
class NotAuthenticated(APIException):
    status_code = status.HTTP_401_UNAUTHORIZED
    default_detail = _('Authentication credentials were not provided.')
    default_code = 'not_authenticated'

NotAuthenticated会导致一个401错误(缺少用户凭证)

代码语言:javascript
复制
class PermissionDenied(APIException):
    status_code = status.HTTP_403_FORBIDDEN
    default_detail = _('You do not have permission to perform this action.')
    default_code = 'permission_denied'

而PermissionDenied会返回错误403(拒绝授权访问)

在向permission_denied()类传递参数时,使用了反射

代码语言:javascript
复制
self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

会在这个权限类对象中寻找message属性,没找到就使用None,而这个参数在后来只会被用在PermissionDenied异常上,这些异常都继承自APIException,而在APIException的构造器中,可以发现detail参数就是异常描述,而在自己的权限类中定义message属性可以改变认证失败后的描述

代码语言:javascript
复制
class APIException(Exception):
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    default_detail = _('A server error occurred.')
    default_code = 'error'

    def __init__(self, detail=None, code=None):
        if detail is None:
            detail = self.default_detail
        if code is None:
            code = self.default_code
    # ...

示例

代码语言:javascript
复制
# api/utils/Permission.py
from rest_framework.permissions import BasePermission


class CommonPermission(BasePermission):
    """
    普通用户权限,作用于全局
    """
    def has_permission(self, request, view):
        print(request.user)
        if request.user.user_type == 1:
            return True

    def has_object_permission(self, request, view, obj):
        """
        一旦获得View权限,将获得所有object权限
        :return: True
        """
        return True


class VipPermission(BasePermission):
    """
    VIP 用户权限
    """
    message = '您首先要称为VIP才能访问'
    
    def has_permission(self, request, view):
        print(request.user)
        if request.user.user_type == 2:
            return True

    def has_object_permission(self, request, view, obj):
        return True
代码语言:javascript
复制
# api/view.py
from django.shortcuts import HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from api.utils.Permission import VipPermission


class LoginView(APIView):
    authentication_classes = []
    # 登录无需权限认证
    permission_classes = []

    def post(self, request, *args, **kwargs):
        pass


@method_decorator(csrf_exempt, name='dispatch')
class ShopView(APIView):
    def get(self, request, *args, **kwargs):
        return HttpResponse(request.user.username)

    def post(self, request, *args, **kwargs):
        return HttpResponse('POST')



class VipIndexView(APIView):
    """
    只授权给VIP用户查看
    """
    permission_classes = [VipPermission]

    def get(self, *args, **kwargs):
        return JsonResponse("welcome VIP ", safe=False)
代码语言:javascript
复制
# RESTdemo.setting.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.MyAuthentication.MyAuthentication'],
    'UNAUTHENTICATED_USER': None,
    'UNAUTHENTICATED_TOKEN': None,
    'DEFAULT_PERMISSION_CLASSES': ['api.utils.Permission.CommonPermission']
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-1-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • REST framework 权限管理源码分析
    • 示例
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档