05 DRF-权限
认证组件 = [认证类,认证类,...] --> 执行每个认证类的authenticate方法:
- 认证成功或失败,不会在执行后续的认证类
- 返回None,执行后续的认证类
- 像是 or
权限组件 = [权限类,权限类,...] --> 执行每个权限类的has_permission方法:
- 认证True通过,False表示不通过
- 执行所有的权限类
- 像是 and
- 学会源码流程后,也可以是 or
默认情况下,保证所有的权限类中的has_permission方法都返回True
1 权限组件应用方式
权限组件应用时:可以局部使用,也可以全局使用。
per.py
import random
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
def has_permission(self, request, view):
# 获取请求中的数据,校验
v1 = random.randint(1, 3)
if v1 == 2:
return True
return False
from ext.per import MyPermission
class OrderView(APIView):
permission_classes = [MyPermission, ] # 应用在单个视图类中
def get(self, request):
return Response('OrderView.')
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER": None,
"DEFAULT_PERMISSION_CLASSES": [
'ext.per.MyPermission',
]
}
2 多个权限类组件应用顺序
import random
from rest_framework.permissions import BasePermission
class MyPermission1(BasePermission):
# 权限验证失败时,读取并返回message
message = {'status': False, 'msg': '无权访问'}
def has_permission(self, request, view):
# 获取请求中的数据,校验
v1 = random.randint(1, 3)
if v1 == 2:
return True
return False
class MyPermission2(BasePermission):
message = {'status': False, 'msg': '无权访问'}
def has_permission(self, request, view):
return False
class MyPermission3(BasePermission):
message = {'status': False, 'msg': '无权访问'}
def has_permission(self, request, view):
return True
from ext.per import MyPermission1, MyPermission2, MyPermission3
class OrderView(APIView):
permission_classes = [MyPermission1, MyPermission2, MyPermission3]
def get(self, request):
return Response({'status': True, 'data': [11, 22, 33]})
多个权限组件认证顺序:首先会按照列表中的顺序来,先认证MyPermission1后依次执行,成功往后执行,失败返回。
只有都成功,认证才会通过。有一个失败,则认证失败。
3 权限认证,错误返回数据
import random
from rest_framework.permissions import BasePermission
class MyPermission1(BasePermission):
# 权限验证失败时,读取并返回message
message = {'status': False, 'msg': '无权访问'}
def has_permission(self, request, view):
# 获取请求中的数据,校验
v1 = random.randint(1, 3)
if v1 == 2:
return True
return False
4 权限认证-扩展
权限认证组件默认条件:是所有的权限类都要通过后,方可通过。
那么我们如何自定义:通过一个权限类,就可以通过呢?
在自己的视图类中重写check_permissions方法:
class OrderView(APIView):
permission_classes = [MyPermission1, ]
def get(self, request):
return Response({'status': True, 'data': [11, 22, 33]})
def check_permissions(self, request):
no_permission_obj = []
for permission in self.get_permissions():
# 当第一个权限类通过,就立即返回
if permission.has_permission(request, self):
return
else:
# 没有通过的权限类加入no_permission_obj
no_permission_obj.append(permission)
else:
self.permission_denied(
request,
message=getattr(no_permission_obj[0], 'message', None),
code=getattr(no_permission_obj[0], 'code', None)
)
5 源码分析
点击查看代码
class Request:
def __init__(self, request, authenticators=None):
self.authenticators = authenticators or ()
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
@user.setter
def user(self, value):
self._user = value
self._request.user = value
def _authenticate(self):
# 读取每个认证组件的对象,执行 authenticate 方法,self=request对象
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
def _not_authenticated(self): # 匿名访问
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
class APIView(View):
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
def permission_denied(self, request, message=None, code=None):
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message, code=code)
def get_permissions(self):
return [permission() for permission in self.permission_classes]
def check_permissions(self, request):
# 读取permission的对象列表
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
for permission in self.get_permissions():
if permission.has_permission(request, self):
return
else:
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
def initial(self, request, *args, **kwargs):
# 认证组件,循环执行每个authticate方法,失败抛出异常;request.user/auth
self.perform_authentication(request)
# 权限组件,假设登录成功,request.user/auth 都有值
self.check_permissions(request)
self.check_throttles(request)
def dispatch(self, request, *args, **kwargs):
self.args = args # url传递的参数接收
self.kwargs = kwargs # url传递的参数接收
# 第一步:请求的封装(django的request对象 + authenticators认证组件)—> 加载认证组件的过车用
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 第二步:request
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 第三步:执行视图函数
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
class OrderView(APIView):
permission_classes = [MyPermission1, ]
def get(self, request):
return Response({'status': True, 'data': [11, 22, 33]})
6 小小应用

ext.view.py:
from rest_framework.views import APIView
class NbApiView(APIView):
def check_permissions(self, request):
no_permission_obj = []
for permission in self.get_permissions():
# 当第一个权限类通过,就立即返回
if permission.has_permission(request, self):
return
else:
# 没有通过的权限类加入no_permission_obj
no_permission_obj.append(permission)
else:
self.permission_denied(
request,
message=getattr(no_permission_obj[0], 'message', None),
code=getattr(no_permission_obj[0], 'code', None)
)

浙公网安备 33010602011771号