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

  

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
#允许任何访问
#不是严格需要,因为可以使用空的权限类,但它会使代码更清晰

  

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方法,返回(用户为真)和(用户被认证为真)的与值

  

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

  

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
#将用户拥有的权限返回

  

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',
),
}

  

  

05-28 20:02