# permissions.py源码分析

## permissions.py 源码分析

```python
SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
#GET请求，HEAD获取头部信息，OPTIONS获取可用请求类型设置为安全方法
#POST，PUT，PATCH，DELETE都会修改数据，没有加到这个元组
```

```python
@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 源码

```python
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 源码

```python
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 源码

```python
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表里的一个字段
```

```python
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 源码

````python
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
#改变一个参数，允许匿名用户的只读访问
````

### 全局设置

```python

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

### 局部设置

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

```python

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

### get权限

```python

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://close.gitbook.io/yun-wei-bi-ji/python/drf/permissions.py-yuan-ma-fen-xi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
