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