Django Rest Framework 权限(Permissions)

90 阅读2分钟

概述

权限(permissions)与身份认证(authentication)和限流(throttling),一起决定是否应该接收请求或拒绝访问。

权限检查始终在视图的开始处运行,在允许继续执行任何其他代码之前运行。权限检查通常会用到身份认证后传入request.userrequest.auth的信息来决定是否允许传入请求。

权限用于授予或拒绝将不同类别的用户访问到API的不同部分。最简单的权限是允许访问任何经过身份验证的用户,并拒绝访问任何未经身份验证的用户。这对应于REST框架中的IsAuthenticated类。稍微严格的权限控制风格是对经过身份验证的用户的允许完全访问,但对未经身份验证的用户的允许只读访问。这对应于REST框架中的IsAuthenticatedOrReadOnly类。

如何确定权限

REST Framework中权限被定义为一个权限类的列表。

运行视图的主体部分前,检查权限列表中的每个权限类。如果权限检查都失败,则会抛出一个exception.PermissionDeniedexceptions.NotAuthenticated异常,并且视图的主体不会运行。

当权限检查失败时,返回的响应的具体规则如下:

  • 请求通过身份验证,但是没有通过权限验证,将返回HTTP 403 Forbidden响应。
  • 请求未通过身份验证,最高优先级的认证类不使用WWW-Authenticateheaders,则返回HTTP 403 Forbidden响应。
  • 请求未通过身份验证,最高优先级的认证类使用WWW-Authenticateheaders,则返回HTTP 401 Unauthorized响应,并且附上WWW-Authenticateheader。

设置权限策略

默认的权限策略可以通过DEFAULT_PERMISSION_CLASSES设置,例如:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

如果未设置,则默认设置为无限制访问:

'DEFAULT_PERMISSION-CLASSES': (
    'rest_framework.permission.AllowAny,
)

还可以在基于APIView的视图类中单独权限策略

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

权限类 源码

BasePermission

class BasePermission(metaclass=BasePermissionMetaclass):
    """
    基础权限类,重写的权限类都继承BasePermission类
    """

    def has_permission(self, request, view):
        """
        如果授予权限,返回True;否则返回None
        """
        return True

    def has_object_permission(self, request, view, obj):
        """
        如果授予权限,返回True;否则返回None
        """
        return True

AllowAny

class AllowAny(BasePermission):
    """
    Allow any access.
    This isn't strictly required, since you could use an empty
    permission_classes list, but it's useful because it makes the intention
    more explicit.
    """

    def has_permission(self, request, view):
        return True

IsAuthenticated

class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_authenticated)

IsAdminUser

class IsAdminUser(BasePermission):
    """
    只允许管理员用户访问。
    """
    def has_permission(self, request, view):
        return bool(request.user and request.user.is_staff)

IsAuthenticatedOrReadOnly

class IsAuthenticatedOrReadOnly(BasePermission):
    """
    如果是只读请求,不需要身份验证;
    否则需要身份验证
    """

    def has_permission(self, request, view):
        return bool(
            # SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
            request.method in SAFE_METHODS or 
            request.user and
            request.user.is_authenticated
        )