登錄認證、認證類、許可權類和頻率類 限制

今日內容概要

  • 認證
  • 頻率
  • 許可權

內容詳細

1、登錄認證


# 要求(登錄介面):
	登陸成功,只要給前端返回json格式字元串 字元串中帶一個隨機字元串
    
# 登陸認證
	判斷用戶是否登錄了 
	前後端分離---》用不到cookie---》攜帶隨機字元串過來---》通過判斷隨機字元串判斷這個人是否登錄了
    
    
# 登陸介面編寫步驟
	創建表:User表,一對一UserToken表
	前端傳入用戶名,密碼
	User表中查,如果能查到---》讓他登陸成功
	成功後在UserToken中存一條記錄---》返回給前端json格式字元串---》字元串中帶一個隨機字元串

新建項目 創建表 models.py:

from django.db import models

class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    user_type = models.IntegerField(choices=((1, '超級管理員'), (2, '普通管理員'), (3, '普通用戶'), (4, '2b用戶')))


class UserToken(models.Model):
    user = models.OneToOneField(to=User, on_delete=models.CASCADE)
    token = models.CharField(max_length=32)
    
# user表中自行添加一條用於測試登錄的數據

視圖類 views.py功能:

from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User, UserToken
import uuid
from rest_framework.response import Response


# class UserView(ViewSetMixin,APIView):  # 等同下面
class UserView(ViewSet):
    # authentication_classes = []  # 局部禁用

    @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 user:
            # 登陸成功--生成一個隨機字元串--存到token表中(如果之前有記錄--更新,如果沒有--新增)
            # uuid生成不重複的串---理論上不重複
            token = str(uuid.uuid4())  # 偽隨機數生成,沒有參數,重複概率,比其他的高一些
            UserToken.objects.update_or_create(user=user, defaults={'token': token})  # 如果存在就更新,如果不存在就新增
            return Response({'code': 100, 'msg': '登陸成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用戶名或密碼錯誤'})

修改路由 urls.py:

from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from app01 import views

router = SimpleRouter()
router.register('user', views.UserView, 'user')
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include(router.urls)),
]

image

2、認證類

# 認證類:
	用來校驗用戶是否登錄,如果登錄了,繼續往下走,如果沒有登錄,直接返回
    
# 編寫步驟:
	一: 寫一個類,繼承BaseAuthentication,重寫authenticate,在方法中做校驗,校驗是否登錄,返回兩個值,沒有登錄拋異常
        
	二:編寫認證類 --》全局使用,局部使用
		全局配置:配置文件中:
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auth.LoginAuth", ]
}

		局部配置:在視圖類中
class UserView(ViewSet):
    authentication_classes = []  # 局部禁用
        
		局部禁用:
class UserView(ViewSet):
    authentication_classes = []  # 局部禁用

# 認證類中返回的兩個變數,幹啥用了
	返回的第一個,給了request.user,就是當前登錄用戶
	返回的第二個,給了request.auth,就是token串

在 models.py添加表:

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    author = models.CharField(max_length=32)
    
# 記得遷移資料庫 並添加一條數據用於測試介面

新建 serializer.py:

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

添加路由 urls.py:

router.register('books', views.BookView, 'books')

新建 auth.py :

from rest_framework.authentication import BaseAuthentication
from .models import UserToken
from rest_framework.exceptions import AuthenticationFailed


# 編寫認證類 步驟:
# 一: 寫一個類,繼承BaseAuthentication,重寫authenticate,在方法中做校驗,校驗是否登錄,返回兩個值,沒有登錄拋異常
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 前端帶過來的token,放在哪,是介面(我們)固定的
        token = request.query_params.get('token')
        user_token = UserToken.objects.filter(token=token).first()
        if user_token:  # 登錄了
            # 返回兩個值:第一個:當前登錄用戶,第二個:token返回
            return user_token.user, token
        else:
            # 拋出認證失敗的異常
            raise AuthenticationFailed('您沒有登錄')

# 二:全局使用,局部使用
# 局部使用:在視圖類在中添加:authentication_classes = [LoginAuth, ]
# 全局使用:在配置文件中配置

image

3、許可權

# 要求:
	用戶是普通用戶---》普通用戶可以訪問所有和單條
	普通管理員和超級用戶可以操作所有,除了訪問單條和所有 的那個視圖類,還要加上認證類

# 跟寫認證類步驟差不多
	第一步:
		寫一個類,繼承BasePermission,重寫has_permission,判斷如果有許可權,返回True,如果沒有許可權,返回False
        
	第二步:局部使用和全局使用
		局部使用:
	class BookDetailView(GenericViewSet, CreateModelMixin, DestroyModelMixin, UpdateModelMixin):
    permission_classes = [UserPermission, ]
    
		全局使用:配置文件中配置(一般不建議使用)
REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES":["app01.auth.UserPermission",]
}

views.py中 添加:

# 許可權類功能:
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin


# 普通用戶,只能查看
class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin):
    authentication_classes = [LoginAuth, ]  # 認證類限制
    queryset = Book.objects.all()
    serializer_class = BookSerializer



from .auth import UserPermission

# 普通用戶以上,才能修改
class BookDetailView(GenericViewSet, CreateModelMixin, DestroyModelMixin, UpdateModelMixin):
    authentication_classes = [LoginAuth, ]  # 認證類限制
    permission_classes = [UserPermission, ]  # 許可權限制
    queryset = Book.objects.all()
    serializer_class = BookSerializer

auth.py 中:

# 編寫許可權類
from rest_framework.permissions import BasePermission


class UserPermission(BasePermission):
    def has_permission(self, request, view):
        self.message = '您是:%s,沒有許可權' % request.user.get_user_type_display()  # 沒有許可權的提示資訊
        # 如果有許可權,返回True,沒有許可權返回False
        # 許可權類,在認證類之後,request.user已經有了當前登錄用戶資訊
        user_type = request.user.user_type
        if user_type < 3:  # 只要不是1,2,就沒有許可權
            return True
        else:
            return False

路由添加 urls.py:

router.register('books', views.BookView, 'books')  # 查看一條,和所有

router.register('booksdetail', views.BookDetailView, 'booksdetail')  # 刪除,新增,修改---》許可權類加在這裡

image

4、頻率限制

# 認證,許可權都通過以後,限制某個介面的訪問頻率 一般根據ip或者用戶限制


# 使用步驟
	第一步:
		寫一個類,繼承SimpleRateThrottle,重寫類屬性:scope,和get_cache_key方法
		get_cache_key返回什麼,就以什麼做現在,scope配置文件中要用
    
	第二步:在配置文件中配置
# 頻率限制
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        'minute_3': '3/m',  # 一分鐘訪問3次
        # 'minute_5': '5/m'  # 一分鐘訪問5次
    }
}


	局部使用--視圖類中:
# 普通用戶,只能查看
class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin):
    authentication_classes = [LoginAuth, ]  # 認證類限制
    throttle_classes = [IPThrottle]  # 頻率限制
    
    
	全局使用--配置文件中:
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': {  # 全局配置頻率類
        'app01.auth.IPThrottle'
    }
}

auth.py中:

# 編寫頻率限制類
from rest_framework.throttling import SimpleRateThrottle


class IPThrottle(SimpleRateThrottle):
    scope = 'minute_3'  # 隨便寫

    def get_cache_key(self, request, view):
        # 返回什麼,就以什麼做限制
        # 限制ip地址---》就在 request.META字典中---》請求頭中數據
        return request.META.get('REMOTE_ADDR')  # 以客戶端ip地址限制
        # return request.user.id  # 以用戶id限制


# class UserThrottle(SimpleRateThrottle):
#     def get_cache_key(self, request, view):
#         scope = 'minute_5'  # 隨便寫
#         # 返回什麼,就以什麼做限制
#         # 限制ip地址---》就在 request.META字典中---》請求頭中數據
#         return request.user.id  # 以用戶id限制

views.py 許可權類中:

# 普通用戶,只能查看
class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin):
    authentication_classes = [LoginAuth, ]  # 認證類限制
    throttle_classes = [IPThrottle]  # 頻率限制

配置文件配置限制:

# 頻率限制
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        'minute_3': '3/m',  # 一分鐘訪問3次
        # 'minute_5': '5/m'  # 一分鐘訪問5次
    }
}

image