DjangoRestFramework之认证组件,权限组件,频率组件,分页组件
一 . 认证组件
我们现在知道的认证机制有cookie, session,session比较安全,session的信息是存在服务器上的,
如果用户量足够大的话,服务器的压力也就比较大,并且django的session存到了django_session表中,不是很好操作,现在生产中使用的一个叫做token机制的方式比较多.
可以使用这个机制把token存到用户信息里,当用户登录成功的时候放里面,等他来的时候就要带着这个来,而且们每次来的时候都更新token,防止被拦截.
我们这里使用一下token,首先要建一个表,和user表一对一关系
models.py
class User(models.Model):
username = models.CharField(max_length=16)
password = models.CharField(max_length=16)
types = ((1, 'VIP'), (2, 'SVIP'), (3, 'SSVIP'))
usertype = models.IntegerField(choices=types, default=1)
class UserToken(models.Model):
user = models.OneToOneField('User')
token = models.CharField(max_length=64)
URL
url(r'^login/$', views.LoginView.as_view()), # 别忘了$符号结尾
视图函数,每次登录后自动刷新token
import uuid
# 用户登录认证
class UserAuth(APIView):
RET = {
'code': None,
'userinfo': None,
'msg': None,
'token': None
}
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
user_obj = models.User.objects.filter(username=username, password=password).first()
if user_obj:
random_str = uuid.uuid4()
models.UserToken.objects.update_or_create( # 有就更新,没有就创建
user=user_obj,
defaults={
'token': random_str,
}
)
self.RET['code'] = 0 # 跟前端约定好,0表示成功
self.RET['userinfo'] = username
self.RET['msg'] = 'success'
self.RET['token'] = random_str
else:
self.RET['code'] = -1
self.RET['userinfo'] = username
self.RET['msg'] = 'failure'
return Response(self.RET)
我们这里写一下DRF的认证组件
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication
from app01 import models
# drf提供认证失败的异常
class UserAuthToken(BaseAuthentication):
# authenticate方法是固定的,并且必须写这个名字,是request新对象
def authenticate(self, request):
token = request.query_params.get('token') # 类似于GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if token_obj:
return token_obj.user, token # 要么就返回两个值,要么就不返回
else:
return AuthenticationFailed('认证失败')
我们需要把这个认证组件 写到每一个url对应的视图函数中,加上认证,有token就可以访问,没有就拒绝
class BookHandle(APIView):
authentication_classes = [UserAuthToken, ] #一进到这个函数就进行验证,变量名必须是这个,认证组件需要从所在文件中导入
# 获取所有数据
def get(self, request):
book_obj_list = models.Book.objects.all()
book_res = BookSerializer(book_obj_list, many=True)
return Response(book_res.data)
需要补两张成功与失败的对比图!!!
全局视图组件(写在settings.py中)
二 . 权限组件
权限组件
from rest_framework.permissions import BasePermission
class UserPermission(BasePermission):
message = "SVIP才能访问!" # 变量只能叫做message,权限不够的话返回message里面的数据
def has_permission(self, request, view): # view是用权限的视图函数
if request.user.usertype == 3: # user表中usertype的字段表示权限级别
return True # 通过权限,只能写True或False
return False # 没有通过
视图函数
class BookHandle(APIView):
permission_classes = [UserPer, ] # 一进函数就验证,只有有权限的才能访问下面的数据
# 获取所有数据
def get(self, request):
book_obj_list = models.Book.objects.all()
book_res = BookSerializer(book_obj_list, many=True)
return Response(book_res.data)
全局视图权限(写在settings.py文件)
三 . 频率组件
内置的throttles类
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope="visit_rate" # 限制访问次数用的
def get_cache_key(self, request, view): # 这个方法是固定的
return self.get_ident(request)
视图函数
class BookHandle(APIView):
throttle_classes = [VisitThrottle, ] # 添加访问频率,需要从该类所在位置引入
# 获取所有数据
def get(self, request):
book_obj_list = models.Book.objects.all()
book_res = BookSerializer(book_obj_list, many=True)
return Response(book_res.data)
四 . 分页组件
视图函数
from rest_framework.pagination import PageNumberPagination
class BookHandle(APIView):
# 获取所有数据
def get(self, request):
book_obj_list = models.Book.objects.all()
# 创建分页器对象
pagenum = PageNumberPagination()
# 通过分页器的paginate_queryset 方法进行分页
page_book_list = pagenum.paginate_queryset(book_obj_list, request)
book_res = BookSerializer(page_book_list, many=True)
return Response(book_res.data)
可以在全局限制每页显示多少个
当然了,也可以自定义page_size
from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
# 下面这些参数只能叫固定的名字
page_size = 3 #每页数据显示条数
page_query_param = 'pp' #http://127.0.0.1:8000/books/?pp=1,查询第一页的数据
page_size_query_param = 'size' # 用做自定义显示数据http://127.0.0.1:8000/books/?pp=2&size=5 #正常是显示3个,这样写就显示5个
max_page_size = 10 #最大每页展示多少条,即便是你前端通过page_size_query_param临时调整了page_size的值,
但是最大也不能超过我们设置的max_page_size的值
class BookHandle(APIView):
# 获取所有数据
def get(self, request):
book_obj_list = models.Book.objects.all()
pagenum = MyPagination()
page_book_list = pagenum.paginate_queryset(book_obj_list, request)
book_res = BookSerializer(page_book_list, many=True)
return Response(book_res.data)
继承ModelViewSet的视图函数使用分页器
from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
page_size = 3
page_query_param = 'pp'
page_size_query_param = 'size'
max_page_size = 10
class CAuthorHandle(ModelViewSet):
queryset = models.Author.objects.all() # 变量名必须是这个
serializer_class = AuthorSerializer # 变量名必须是这个
pagination_class = MyPagination #配置我们自己写的分页类