REST framework 权限管理源码分析

REST framework 权限管理源码分析

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

    def initial(self, request, *args, **kwargs):
        # .......
        # 用户认证
        self.perform_authentication(request)
        # 权限控制
        self.check_permissions(request)
        # ...

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

    # 权限管理
    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代表没有权限.

    def get_permissions(self):
        return [permission() for permission in self.permission_classes]

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

    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异常

class NotAuthenticated(APIException):
    status_code = status.HTTP_401_UNAUTHORIZED
    default_detail = _('Authentication credentials were not provided.')
    default_code = 'not_authenticated'

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

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()类传递参数时,使用了反射

self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

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

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
    # ...

示例

# 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

# 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)

# 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']
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Junebao

如果你碰巧财力雄厚的话...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值