drf -三大权限认证例子

三大权限认证测试例子代码

models.py

from django.db import models


# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)


class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    # user_type区分是什么类型用户:超级管理员 1,普通用户 2, 2b用户 3
    user_type = models.IntegerField(default=3, choices=((1, '超级管理员'), (2, '普通用户'), (3, '2b用户')))
    # 其实choice本质就是有关联,后期不会修改的情况下使用choice,后期会增加或减少用户类型的情况下,要使用另一个表
    # user_type = models.IntegerField(default=1)

    #外键关联
    def __str__(self):
        return self.username


# 用户登录记录表
# 如何区分用户是否登录了?
class UserToken(models.Model):
    # SET_NULL   SET_DEFAULT   CASCADE  SET(函数内存地址)
    # 用户如果没有登录,就是空,如果登录了,就有值,登录多次以最后一次为准
    user = models.OneToOneField(to='User', on_delete=models.CASCADE)
    token = models.CharField(max_length=32, null=True)

pycharm ->tools-run manage.py

makemigration ->migrate

urls.py

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

from rest_framework.routers import DefaultRouter, SimpleRouter

# 自动生成路由
# drf提供了两个路由类,以后继承了ViewSetMixin及其子类的视图类,就可以使用这两个路由类来自动生成路由
# 第一步:导入路由类
# 第二步实例化对象
router = SimpleRouter()
# 第三步:注册路由(注册多个)
# 第一个参数:路径 第二个参数:视图类 第三个参数:别名,可以不写
router.register('user', views.UserView, 'user')
router.register('books', views.BookView, 'books')
router.register('publish', views.PublishView, 'publish')

## 第四步:把自动生成的路由添加到urlpatterns中
# 第四步
urlpatterns = [
    path('admin/', admin.site.urls),
    # 方式一
    path('', include(router.urls)),
]

views.py

from django.shortcuts import render
from rest_framework.views import APIView

from .models import Book, Publish
from rest_framework.viewsets import ViewSetMixin, ViewSet, GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
from .serializer import BookSerializer, PublishSerializer
from rest_framework.response import Response
from rest_framework.decorators import action
from .models import User, UserToken
import uuid


class BookView(ModelViewSet):
    serializer_class = BookSerializer
    queryset = Book.objects.all()


class PublishView(ModelViewSet):
    # 关闭登录认证
    authentication_classes = []
    # 关闭权限认证
    permission_classes = []
    serializer_class = PublishSerializer
    queryset = Publish.objects.all()

    def list(self, request, *args, **kwargs):
        # self:是视图类的对象
        print(request.user)
        print(request.auth)
        return super().list(request, *args, **kwargs)


class UserView(ViewSet):
    # 关闭登录验证
    authentication_classes = []
    # 关闭访问权限认证
    permission_classes = []

    @action(methods=['POST', ], detail=False, url_path='login')
    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 = str(uuid.uuid4())  # 生成一个随机字符串

            UserToken.objects.update_or_create(defaults={'token': token}, user=user)

            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:

            return Response({'code': 101, 'msg': '用户名或密码错误'})

新建auth,permission,throttling

auth.py:写登录认证类

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

from app01.models import UserToken


class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        print(request.META)
        # 在这里做认证,校验用户是否登录(带了token,并且能查到,就是登录,返回两个值,否则就是没登录,抛异常)
        # 用户带的token从哪取?后端人员定的:放在请求地址中
        # token = request.GET.get('token')
        login_token = request.GET.get('token')
        # 通过什么验证呢?我们有token.还有什么?
        # 通过token查询该token是否是在表中有记录
        token_data = UserToken.objects.filter(token=login_token).first()
        if token_data:
            # 返回两个值,一个是当前登录用户,一个是token
            return token_data.user, login_token
        else:
            raise AuthenticationFailed('您未登录')

permission.py:权限认证类

from rest_framework.permissions import BasePermission


class UserTypePermission(BasePermission):
    def has_permission(self, request, view):
        if request.user.user_type == 1:
            return True
        else:
            # self.message = '普通用户和2b用户都没有权限' # 返回给前端的提示是什么样
            # 使用了choice后,user.user_type 拿到的是数字类型,想变成字符串 user.get_user_type_display()
            self.message = '您是:%s 用户,您没有权限' % request.user.get_user_type_display()
            return False

throttling.py: 访问频率类

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle


class MyThrottling(SimpleRateThrottle):  # 我们继承SimpleRateThrottle去写,而不是继承BaseThrottle去写
    # 类属性,这个类属性可以随意命名,但要跟配置文件对应
    scope = 'diga'

    def get_cache_key(self, request, view):
        # 返回什么,频率就以什么做限制
        # 可以通过用户id限制
        # 可以通过ip地址限制
        return request.META.get('REMOTE_ADDR')

settings.py

#开启登录认证,权限认证
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.auth.LoginAuth', ],
    'DEFAULT_PERMISSION_CLASSES': ['app01.permission.UserTypePermission'],
    'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.MyThrottling'],
    'DEFAULT_THROTTLE_RATES': {
        'diga': '3/m'
    }
}

登录认证测试结果

image

image

权限认证测试结果

image

image

访问频率测试解结果

image

image

posted @ 2022-10-09 18:47  名字长的像一只老山羊  阅读(51)  评论(0编辑  收藏  举报