• django-rest-framework 基础三 认证、权限和频率


    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 GenericViewSet
    from authenticated.models import User,UserToken
    from rest_framework.response import Response
    from rest_framework.decorators import action
    import uuid
    
    class 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 admin
    from django.urls import path,include
    from authenticated import views
    from rest_framework import routers
    
    router = 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 BaseAuthentication
    class 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 BaseAuthentication
    from authenticated.models import  UserToken
    from rest_framework.exceptions import AuthenticationFailed
    
    class 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 GenericViewSet
    from authenticated.models import User,UserToken
    from rest_framework.response import Response
    from rest_framework.decorators import action
    import uuid
    
    
    from rest_framework.viewsets import ModelViewSet
    from authenticated.models import Book
    from authenticated.serializer import BookSerializer
    from authenticated.authentication import LoingAuth
    
    class 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 admin
    from django.urls import path,include
    from authenticated import views
    from rest_framework import routers
    
    router = 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 BasePermission
    
    
    class 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 GenericViewSet
    from authenticated.models import User, UserToken
    from authenticated.models import Book
    from authenticated.serializer import BookSerializer
    from authenticated.authentication import LoingAuth
    from 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 userPermission
    
    
    class BookDetailView(GenericViewSet, CreateModelMixin, UpdateModelMixin, DestroyModelMixin):
        authentication_classes = [LoingAuth]
        permission_classes = [userPermission]
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
    

    路由 urls.py:

    from django.contrib import admin
    from django.urls import path,include
    from authenticated import views
    from rest_framework import routers
    
    router = 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 = []  # 让它等于空就可以了。
    

    普通用户访问的时候会报没有权限

    image-20220405011610943

    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 SimpleRateThrottle
    
    class 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次就会报错:

    image-20220405020938862

    上面的配置为局部配置,也可以设置全局配置

    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次
        },
    }
    
  • 相关阅读:
    javaweb网络教学及评价系统
    分布式学习 - MPICH编译与实践
    CMAK Kafka可视化管理工具
    【数据结构】图的广度优先遍历
    分类预测 | MATLAB实现SSA-CNN-LSTM-Attention数据分类预测(SE注意力机制)
    Appium环境搭建及元素定位
    如何评测一个大模型?(微软亚洲研究院 )
    怎么在Qt中使用AIUI
    【知识网络分析】引文网络(citation)
    神经网络入门(一)
  • 原文地址:https://www.cnblogs.com/hans-python/p/16251241.html