django-rest-framework 基础三 认证、权限和频率
小刘 2022-08-15 15:15:05 2022-08-15 45 0
django-rest-framework 基础三 认证、权限和频率
目录
1. 认证
登录接口: 登录成功只要给前端返回json格式字符串,这个字符串中带一个随机字符串(可以使用uuid生成)
登录接口步骤:
前端传入用户名和密码,然后去user表中查找,能找到说明用户和密码没问题,登录成功,然后在userToken表中存一条记录,说明登录过了,再返回前端一个json字符串
1.1 登录接口
models.py
from django.db import models# Create your models here.class User(models.Model): username = models.CharField(max_length=64) password = models.CharField(max_length=128) user_type = models.IntegerField(choices=((1, "超级管理员"),(2,"管理员"),(3,"普通用户")))class UserToken(models.Model): user = models.OneToOneField(to=User,on_delete=models.CASCADE) userToken = models.CharField(max_length=64)
views.py
from django.shortcuts import render# Create your views here.from rest_framework.viewsets import GenericViewSetfrom authenticated.models import User,UserTokenfrom rest_framework.response import Responsefrom rest_framework.decorators import actionimport uuidclass UserView(GenericViewSet): @action(methods=['POST'], detail=False) def login(self,request): username = request.data.get("username") password = request.data.get("password") user = User.objects.filter(username=username, password=password).first() if not user: return Response({"code":1001,"msg":"用户名或密码错误"}) token = str(uuid.uuid4()) # 获取一个不重复的值,做唯一标识 # userToken表中有就更新,没有就创建 #UserToken.objects.update_or_create(user=user, defaults={'token': token}) UserToken.objects.update_or_create(user=user, defaults={'userToken': token}) # 返回信息,并带着token return Response({"code":1000,"msg":"登录成功",'userToken': token})
urls.py
from django.contrib import adminfrom django.urls import path,includefrom authenticated import viewsfrom rest_framework import routersrouter = routers.SimpleRouter()router.register('user',views.UserView, "user")urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls))]
访问:
post请求: http://127.0.0.1:8000/user/login/
1.2 认证
有了登录接口,就可以实现认证,如果要调用别的接口必须要先登录才可以。
例如有个图书的表有五个接口,要访问图书的五个接口必须就登录。
步骤:
1. 先写一个类,继承BaseAuthentication,并重写authenticate方法,在方法中校验是否登录,登录则返回两个值,没有则拋异常from rest_framework.authentication import BaseAuthenticationclass xxxx(BaseAuthentication): def authenticate(self, request): 2. 全局配置和局部配置全局配置:settings.py中 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES":["authenticated.authentication.LoingAuth"]}局部配置:在视图类中:authentication_classes = [xxxx,]禁止局部署配置:authentication_classes = []登录则返回两个值: request.user 当前登录的用户 request.auth 为当前登录用户的token
示例:
models.py
from django.db import models# Create your models here.class User(models.Model): username = models.CharField(max_length=64) password = models.CharField(max_length=128) user_type = models.IntegerField(choices=((1, "超级管理员"),(2,"管理员"),(3,"普通用户")))class UserToken(models.Model): user = models.OneToOneField(to=User,on_delete=models.CASCADE) userToken = models.CharField(max_length=64)class Book(models.Model): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=5, decimal_places=2) author = models.CharField(max_length=64)
认证功能,在app中新建authentication.py
from rest_framework.authentication import BaseAuthenticationfrom authenticated.models import UserTokenfrom rest_framework.exceptions import AuthenticationFailedclass LoingAuth(BaseAuthentication): def authenticate(self, request): token = request.query_params.get('token') user_token = UserToken.objects.filter(userToken=token).first() if not user_token: raise AuthenticationFailed("请先登录") return user_token.user, token
views.py
from django.shortcuts import render# Create your views here.from rest_framework.viewsets import GenericViewSetfrom authenticated.models import User,UserTokenfrom rest_framework.response import Responsefrom rest_framework.decorators import actionimport uuidfrom rest_framework.viewsets import ModelViewSetfrom authenticated.models import Bookfrom authenticated.serializer import BookSerializerfrom authenticated.authentication import LoingAuthclass UserView(GenericViewSet): @action(methods=['POST'], detail=False) def login(self,request): username = request.data.get("username") password = request.data.get("password") user = User.objects.filter(username=username, password=password).first() if not user: return Response({"code":1001,"msg":"用户名或密码错误"}) token = str(uuid.uuid4()) # userToken表中有就更新,没有就创建 #UserToken.objects.update_or_create(user=user, defaults={'token': token}) UserToken.objects.update_or_create(user=user, defaults={'userToken': token}) return Response({"code":1000,"msg":"登录成功",'token': token})class BookView(ModelViewSet): # 只对BookView单独进行认证(局部配置) authentication_classes = [LoingAuth,] queryset = Book.objects.all() serializer_class = BookSerializer
路由urls.py
from django.contrib import adminfrom django.urls import path,includefrom authenticated import viewsfrom rest_framework import routersrouter = routers.SimpleRouter()router.register('user',views.UserView, "user")router.register('books', views.BookView,"books")urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls))]
全局配置settings.py
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES":["authenticated.authentication.LoingAuth"],}# authenticated.authentication.LoingAuth 为写的认证的类# 全局配置后局部配置的就可以取消了。# 但是全局配置后如果有些类不想让它有认证,比如登录接口,它不能有认证否则就死循环了。# 全局配置后,单独取消某一个接口的认证: class UserView(ViewSet): authentication_classes = [] # 让它等于空就可以了。
2. 权限
所有的接口必须登录后才能访问(给每个视图加认证),登录成功后如果是普通用户则只可查看全部或单条数据。如果想要增删改必须是管理员或超级管理员。
演示可以把五个接口写成两个视图:
在应用目录下创建permission.py文件
permission.py
from rest_framework.permissions import BasePermissionclass userPermission(BasePermission): def has_permission(self, request, view): user_type = request.user.user_type # (1, "超级管理员"),(2,"管理员"),(3,"普通用户"),如果小于3说明是管理或超管用户 if user_type <3: return True else: return False
视图views.py
from rest_framework.viewsets import GenericViewSetfrom authenticated.models import User, UserTokenfrom authenticated.models import Bookfrom authenticated.serializer import BookSerializerfrom authenticated.authentication import LoingAuthfrom rest_framework.mixins import CreateModelMixin, ListModelMixin, DestroyModelMixin, UpdateModelMixin, \ RetrieveModelMixin #用户登录接口此处省略(见上面1.2认证) # 查看全部和单条。只要登录了谁都可以访问class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin): authentication_classes = [LoingAuth, ] queryset = Book.objects.all() serializer_class = BookSerializer# 只有管理和超管用户可以 创建、修改、新增from authenticated.permission import userPermissionclass BookDetailView(GenericViewSet, CreateModelMixin, UpdateModelMixin, DestroyModelMixin): authentication_classes = [LoingAuth] permission_classes = [userPermission] queryset = Book.objects.all() serializer_class = BookSerializer
路由 urls.py:
from django.contrib import adminfrom django.urls import path,includefrom authenticated import viewsfrom rest_framework import routersrouter = routers.SimpleRouter()router.register('user',views.UserView, "user")router.register('books', views.BookView,"books")router.register('bookdetail', views.BookDetailView,"bookdetail")urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls))]
全局配置settings.py
REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES":["authenticated.permission.userPermission"],}# authenticated.permission.userPermission 为写的权限的类# 全局配置后局部配置的就可以取消了。# 全局配置后,单独取消某一个接口的权限: class UserView(ViewSet): permission_classes = [] # 让它等于空就可以了。
普通用户访问的时候会报没有权限
2.1 权限总结:
两个视图:
BookView:获取所有,获取单条BookDetailView:删除,修改,新增上面两个视图都需要登录:authentication_classes = [LoginAuth, ]BookDetailView必须有权限才能,加了一个权限,permission_classes = [UserPermission, ]
编写权限步骤
第一步:写一个类,继承BasePermission,重写has_permission,判断如果有权限,返回True,如果没有权限,返回False第二步:局部配置和全局配置局部配置 class BookDetailView(GenericViewSet, CreateModelMixin, DestroyModelMixin, UpdateModelMixin): permission_classes = [UserPermission, ] 全局配置 settings.py REST_FRAMEWORK={ "DEFAULT_PERMISSION_CLASSES":["authenticated.permission.userPermission",] }
3. 频率
限制访问的频率
在应用目录创建throttle.py文件用来限制频率
throttle.py
from rest_framework.throttling import SimpleRateThrottleclass IpThrottle(SimpleRateThrottle): scope = 'min_3' # 在settings.py定义给哪个类限制的频率 # get_cache_key 返回什么就以什么做限制,现在是以IP做限制 def get_cache_key(self, request, view): return request.META.get('REMOTE_ADDR') # 返回的是客户端的IP,以IP做限制 # return request.user.id # 返回已经登录的用户的id,以用户id做限制
views.py
from authenticated.throttle import IpThrottle# 查看全部和单条。只要登录了谁都可以访问class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin): authentication_classes = [LoingAuth, ] throttle_classes = [IpThrottle] # 访问BookView类做限制 queryset = Book.objects.all() serializer_class = BookSerializer
settings.py
REST_FRAMEWORK = { "DEFAULT_THROTTLE_RATES":{ 'min_3':'3/m', },}# min_3 就是上面throttle.py.IpThrottle里scope定义的,这个一定要和scope定义的一致# 3/m 每一分钟访问3次 ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')# 如果throttle.py.IpThrottle里还有别的限制的类,如果scope也是为min_3,那它也是每分钟访问3次的限制
超过3次就会报错:
上面的配置为局部配置,也可以设置全局配置
settings.py
REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASSES" : ["authenticated.throttle.IpThrottle"], # 全局配置 "DEFAULT_THROTTLE_RATES":{ 'min_3':'3/m', },}# 同样设置了全局,局部的throttle_classes = [IpThrottle]就可以不写了# 如果只是某个类禁用:throttle_classes = []
3.1 频率总结
步骤:
第一步:写一个类,继承SimpleRateThrottle,重写类属性:scope,和get_cache_key方法 get_cache_key返回什么,就以什么做限制, scope配置文件中要用 第二步:在配置文件中配置settings.py中REST_FRAMEWORK = { "DEFAULT_THROTTLE_RATES":{ 'min_3':'3/m', # minute_3是scope的字符串,一分钟访问3次 },}第三步: 使用1. 局部使用--》视图类中 class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin): throttle_classes = [IPThrottle] 2. 全局使用--配置文件中settings.py中REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASSES" : ["authenticated.throttle.IpThrottle"], "DEFAULT_THROTTLE_RATES":{ 'min_3':'3/m', # minute_3是scope的字符串,一分钟访问3次 },}