Django REST 框架详解 09 | 权限组件
程序员文章站
2022-04-25 15:49:43
...
一、权限组件
1. 分析源码
通过分析源码了解权限组件的方法调用过程
APIView 的 dispatch 中使用 initial 方法实现初始化并进行三大认证,第二步进行权限组件调用
rest_framework/views.py
class APIView(View):
# ...
# 定义默认权限类
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
def initial(self, request, *args, **kwargs):
# ...
# 认证组件:校验用户
# 这里调用 perform_authentication 实现认证
self.perform_authentication(request)
# 权限组件:校验用户权限
self.check_permissions(request)
# 频率组件:限制视图接口被访问次数
self.check_throttles(request)
# 权限认证
def check_permissions(self, request):
# 遍历权限对象列表得到一堆权限器,进行权限认证
for permission in self.get_permissions():
# 权限类 has_permission 做权限认证
# 参数:权限对象self,请求对象request,视图类对象
# 返回值:有权限返回 True,无权限返回 False
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
# 获取权限
def get_permissions(self):
# 由权限类定义
return [permission() for permission in self.permission_classes]
在 drf 设置文件查看默认权限配置
rest_framework/settings.py
# 默认权限类配置
DEFAULTS = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
}
查看默认系统权限的实现
rest_framework/permissions.py
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)
class IsAdminUser(BasePermission):
# is_staff:后台管理用户
# 后台管理用户由所有权限,游客无权限
def has_permission(self, request, view):
return bool(request.user and request.user.is_staff)
class IsAuthenticatedOrReadOnly(BasePermission):
def has_permission(self, request, view):
return bool(
# 如果是读请求,不校验用户,直接返回
request.method in SAFE_METHODS or
# 登录用户有所有权限,游客只读
request.user and
request.user.is_authenticated
)
总结以上的系统权限类:
-
AllowAny:游客与登录用户有所有权限
-
IsAuthenticated:登录用户有所有权限,游客无权限
-
IsAdminUser:后台管理用户由所有权限,游客无权限
-
IsAuthenticatedOrReadOnly:登录用户有所有权限,游客只读
2. 全局配置权限
settings.py
# 全局局部配置
REST_FRAMEWORK = {
# 配置默认权限类
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
}
3. 局部配置权限
views.py
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import GenericViewSet, ViewSet
from utils.response import APIResponse
# 只有登录后才能访问
# 这里认证用的是之前的 MyAuthentication
class AuthenticatedAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
return APIResponse(0, 'Authenticated successful')
# 游客只读,用户无限制
class AuthenticatedOrReadOnlyAPIView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def get(self, request, *args, **kwargs):
return APIResponse(0, 'Read successful')
def post(self, request, *args, **kwargs):
return APIResponse(0, 'All successful')
urls.py
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^auth/$', views.AuthenticatedAPIView.as_view()),
url(r'^auth2/$', views.AuthenticatedOrReadOnlyAPIView.as_view()),
]
4. 接口测试
只有登录后才能访问
登录用户和游客可读
登录用户有所有权限
二、自定义权限类
1. 代码实现
-
继承 BasePermission
-
重写 has_permission 方法
-
实现根据自定义权限规则,确定是否有权限
-
认证规则:
-
满足设置的用户条件,代表有权限,返回 True
-
满足设置的用户条件,代表有权限,返回 False
-
-
进行全局或局部配置
- 全局:配置文件 settings.py
- 局部:在视图类 import
-
测试接口:前台在请求头携带认证信息,且默认规范用 Authorization 字段携带认证信息
自定义权限类permissions.py
from rest_framework.permissions import BasePermission, SAFE_METHODS
from django.contrib.auth.models import Group
class MyPermission(BasePermission):
def has_permission(self, request, view):
# values_list(falt=True) 获取列表转为集合,与目标求交集
group = Group.objects.filter(name='administrator').first()
groups = request.user.groups.all()
return bool(
request.method in ('GET', 'HEAD', 'OPTIONS') or
group and groups and
group in groups
)
views.py
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import GenericViewSet, ViewSet
from api.permissions import MyPermission
from utils.response import APIResponse
# 游客和登录用户只读,登录用户属于管理员分组无限制
class AdminOrReadOnlyAPIView(APIView):
permission_classes = [MyPermission]
def get(self, request, *args, **kwargs):
return APIResponse(0, 'Mypermission Read successful')
def post(self, request, *args, **kwargs):
return APIResponse(0, 'Mypermission All successful')
urls.py
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^login/$', views.LoginView.as_view()),
url(r'^auth/$', views.AuthenticatedAPIView.as_view()),
url(r'^auth2/$', views.AuthenticatedOrReadOnlyAPIView.as_view()),
url(r'^auth3/$', views.AdminOrReadOnlyAPIView.as_view()),
]
2. 测试接口
有认证信息且正确,有所有权限
无认证信息,或有错误认证信息,无写权限
无认证信息,有读权限