permissions.py源码分析

permissions.py 源码分析

SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
#GET请求,HEAD获取头部信息,OPTIONS获取可用请求类型设置为安全方法
#POST,PUT,PATCH,DELETE都会修改数据,没有加到这个元组
@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
#所有权限类都该继承它
#两个方法,has_perm,has_obj_perm

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)
#只要认证用户允许访问
#重写了has_permission方法,返回(用户为真)和(用户被认证为真)的与值

IsAdminUser 源码

class IsAdminUser(BasePermission):
    """
    Allows access only to admin users.
    """
 
    def has_permission(self, request, view):
        return bool(request.user and request.user.is_staff)
#只允许管理员用户访问
#is_staff是users表里的一个字段
class IsAuthenticatedOrReadOnly(BasePermission):
    """
    The request is authenticated as a user, or is a read-only request.
    """
 
    def has_permission(self, request, view):
        return bool(
            request.method in SAFE_METHODS or
            request.user and
            request.user.is_authenticated
        )
#认证用户的请求,或者只读请求
#请求方法在SAFE_METHODS 这个元组里则返回True
#请求用户为认证用户也返回True

DjangoModelPermissions 源码

class DjangoModelPermissions(BasePermission):
    """
    The request is authenticated using `django.contrib.auth` permissions.
    See: https://docs.djangoproject.com/en/dev/topics/auth/#permissions
 
    It ensures that the user is authenticated, and has the appropriate
    `add`/`change`/`delete` permissions on the model.
 
    This permission can only be applied against view classes that
    provide a `.queryset` attribute.
    """
 
    # Map methods into required permission codes.
    # Override this if you need to also provide 'view' permissions,
    # or if you want to provide custom permission codes.
    perms_map = {
        'GET': [],
        'OPTIONS': [],
        'HEAD': [],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }
 
    authenticated_users_only = True
 
    def get_required_permissions(self, method, model_cls):
        """
        Given a model and an HTTP method, return the list of permission
        codes that the user is required to have.
        """
        kwargs = {
            'app_label': model_cls._meta.app_label,
            'model_name': model_cls._meta.model_name
        }
 
        if method not in self.perms_map:
            raise exceptions.MethodNotAllowed(method)
 
        return [perm % kwargs for perm in self.perms_map[method]]
 
    def _queryset(self, view):
        assert hasattr(view, 'get_queryset') \
            or getattr(view, 'queryset', None) is not None, (
            'Cannot apply {} on a view that does not set '
            '`.queryset` or have a `.get_queryset()` method.'
        ).format(self.__class__.__name__)
 
        if hasattr(view, 'get_queryset'):
            queryset = view.get_queryset()
            assert queryset is not None, (
                '{}.get_queryset() returned None'.format(view.__class__.__name__)
            )
            return queryset
        return view.queryset
 
    def has_permission(self, request, view):
        # Workaround to ensure DjangoModelPermissions are not applied
        # to the root view when using DefaultRouter.
        if getattr(view, '_ignore_model_permissions', False):
            return True
 
        if not request.user or (
           not request.user.is_authenticated and self.authenticated_users_only):
            return False
 
        queryset = self._queryset(view)
        perms = self.get_required_permissions(request.method, queryset.model)
 
        return request.user.has_perms(perms)
#使用django.contrib.auth权限认证请求
#确保用户被认证,并且在model上拥有合适的add,change,delete的权限
#只有在有queryset属性的类视图上使用
#
#perms_map
#映射方法到权限码
#如果要提供view权限,或者自定义权限码,重写它
#每个method对应一个列表,格式是app_label.codename,比如cmdb.add_gameid
#
#get_required_permissions
#输入一个model和http方法
#如果method没有在perms_map映射表,则抛出错误
#返回权限列表
#
#_queryset
#检查视图中有没有queryset属性或者get_queryset方法,没有则报错。
#
#has_permission
#检查有没有权限
#如果view中定义_ignore_model_permissions则直接返回True
#如果账户没有认证,则返回False
#将用户拥有的权限返回
```  

```python
class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions):
    """
    Similar to DjangoModelPermissions, except that anonymous users are
    allowed read-only access.
    """
    authenticated_users_only = False
#继承自DjangoModelPermissions
#改变一个参数,允许匿名用户的只读访问

全局设置


    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.AllowAny',
    ),
#在rest_framework/settings.py中,默认的权限配置AllowAny
 
REST_FRAMEWORK = {
    ...
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.DjangoModelPermissions',
    ),
}
#可以在项目的settings中,修改为DjangoModelPermissions,这是最常用的

局部设置

  只允许认证用户访问,只对这个viewset生效


from rest_framework.permissions import IsAuthenticated
 
class SvrconfigViewSet(viewsets.ReadOnlyModelViewSet):
    """
    retrieve:
        返回指定信息
    list:
        返回列表
    """
    queryset = Svrconfig.objects.all()
    serializer_class = SvrconfigSerializer
    permission_classes = (IsAuthenticated,)
#给一个视图集设置权限,只有认证用户可以访问
#没有用户信息,会出现401错误

get权限


在DjangoModelPermissions中,默认get是不需要权限的,但业务中的查看一般是需要权限的所以需要重写。

project/permissions.py



#重建权限映射
from rest_framework.permissions import DjangoModelPermissions
 
 
class Permissions(DjangoModelPermissions):
 
    perms_map = {
        'GET': ['%(app_label)s.view_%(model_name)s'],
        'OPTIONS': [],
        'HEAD': [],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }
  

settings.py


REST_FRAMEWORK = {
    ...
    'DEFAULT_PERMISSION_CLASSES': (
        'project.permissions.Permissions',
    ),
}

Last updated