基本使用
问题:不同的视图赋予不同的权限,以用来访问
views.py
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from api import models
ORDER_DICT = {
1: {
'name': 'qiu',
'age': 18,
'gender': '男',
'content': '...'
},
2: {
'name': 'xi',
'age': 19,
'gender': '男',
'content': '.....'
}
}
def md5(user):
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user, encoding='utf-8'))
m.update(bytes(ctime, encoding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
authentication_classes = []
def post(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UerInfo.objects.filter(username=user, password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
# 为登录用户创建token
else:
token = md5(user)
# 存在就更新, 不存在就创建
models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
class OrderView(APIView):
'''
订单相关业务(只有SVIP用户有权限)
'''
def get(self, request, *args, **kwargs):
# 为其添加权限,当为SVIP用户才可以访问
if request.user.user_type != 3:
return HttpResponse('无权访问')
ret = {'code': 1000, 'msg': None, 'data': None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
class UserInfoView(APIView):
'''
用户中心(普通用户、VIP有权限)
'''
def get(self, request, *args, **kwargs):
print(request.user)
return HttpResponse('用户信息')
当 user_type
为 1 时,发送 GET 请求,得到无权访问
若将 user_type
换为 3,则能够访问数据
上面每个不同的视图函数都需要添加一个权限功能,可以将它定义成一个类,在使用的时候直接调用,并且与视图函数区分开,可以在 utils 下新建 permission.py
views.py
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from api import models
from api.utils.permission import MyPermission, MyPermission1
ORDER_DICT = {
1: {
'name': 'qiu',
'age': 18,
'gender': '男',
'content': '...'
},
2: {
'name': 'xi',
'age': 19,
'gender': '男',
'content': '.....'
}
}
def md5(user):
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user, encoding='utf-8'))
m.update(bytes(ctime, encoding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
authentication_classes = []
def post(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UerInfo.objects.filter(username=user, password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
# 为登录用户创建token
else:
token = md5(user)
# 存在就更新, 不存在就创建
models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
class OrderView(APIView):
'''
订单相关业务(只有SVIP用户有权限)
'''
permission_classes = [SVIPPermission]
def get(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None, 'data': None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
class UserInfoView(APIView):
'''
用户中心(普通用户、VIP有权限)
'''
permission_classes = [MyPermission]
def get(self, request, *args, **kwargs):
return HttpResponse('用户信息')
permission.py
# -*- coding: utf-8 -*-
class SVIPPermission(object):
message = "必须是SVIP用户才能访问"
def has_permission(self, request, view):
if request.user.user_type != 3:
return False
return True
class MyPermission(object):
def has_permission(self, request, view):
if request.user.user_type == 3:
return False
return True
源码流程
权限的源码流程几乎和认证是一样的。首先从 dispatch
,然后封装 request
,来到 initial
def initial(self, request, *args, **kwargs):
... # 省略的内容
# Ensure that the incoming request is permitted
self.perform_authentication(request)
# 权限判断
self.check_permissions(request)
self.check_throttles(request)
进入 check_permissions
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
'''
self.get_permissions,首先去 OrderView 中找,没有去父类中找
在父类中返回了权限对象的列表
'''
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
# 对类进行实例化得到权限对象的列表
return [permission() for permission in self.permission_classes]
如果没有对 self.permission_classes
设置,默认去配置文件中查找,如果设置了就使用设置的,之前在 views.py
中设置了 permission_classes
class APIView(View):
...
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
...
也可以将其设置为全剧配置
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthentication', 'api.utils.auth.Authentication'],
'UNAUTHENTICATED_USER': None,
'UNAUTHENTICATED_TOKEN': None,
'DEFAULT_PERMISSION_CLASSES': ['api.utils.permission.SVIPPermission']
}
回到上一步的 check_permissions
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
'''
self.get_permissions,首先去 OrderView 中找,没有去父类中找
在父类中返回了权限对象的列表
'''
for permission in self.get_permissions():
# 如果 permission.has_permission(request, self) 为 False,才走里面的代码
if not permission.has_permission(request, self):
self.permission_denied(
# 这里有个message,是返回给用户看的信息,可以写在自己的权限中
request, message=getattr(permission, 'message', None)
)
def permission_denied(self, request, message=None):
"""
If request is not permitted, determine what kind of exception to raise.
"""
# 抛出异常,权限认证失败
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message)
权限的内置类
认证有内置的认证,权限也有内置的权限,因此在自定义权限的时候,为了更加规范,需要继承
permission.py
from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
message = "必须是SVIP用户才能访问"
def has_permission(self, request, view):
if request.user.user_type != 3:
return False
return True
class MyPermission(BasePermission):
def has_permission(self, request, view):
if request.user.user_type == 3:
return False
return True
总结
1、使用
-
类,继承
BasePermission
,必须实现has_permission
方法 -
返回值
- True:有权访问
- False:无权访问
-
全局
'DEFAULT_PERMISSION_CLASSES': ['api.utils.permission.SVIPPermission']
-
局部
permission_classes = [MyPermission]
2、源码流程
请求进来走 dispatch
,先对 request
封装,然后走 initial
,先做认证,认证完成做权限,权限里面把类拿过来做列表生成式生成对象,循环每一个对象,执行 has_permission
方法