DRF | 入门第七天 三大组件

60 阅读3分钟

登录认证

创建用户表

# 用户表  
class User(models.Model):  
    name = models.CharField(max_length=32)  
    pswd = models.CharField(max_length=32)  
    vip = models.IntegerField(choices=((0, '普通用户'),(1, 'VIP用户'),(2, 'SIV用户'), (3, '超级管理员')))  
    is_delete = models.IntegerField(choices=((0, 'Active'), (1, 'Inactive')))  
  
  
# 令牌表  
class Token(models.Model):  
    token = models.CharField(max_length=64)  
    user = models.OneToOneField(to=User, on_delete=models.CASCADE)

创建视图层

需要注意的是指令的创建和添加

import uuid  
  
from django.shortcuts import render  
from rest_framework.viewsets import ModelViewSet, ViewSet  
from rest_framework.response import Response  
from rest_framework.decorators import action  
from app01.models import User, Token  
  
  
# Create your views here.  
  
  
'''  
需求:  
---1. 路由想要自动生成  
---2. 是否需要序列化  
---3.  
'''  
class UserView(ViewSet):  
  
    @action(methods=['POST'], detail=False)  
    def login(self, request, *args, **kwargs):  
        # 接收前端传入的数据  
        name = request.data.get('name')  
        pswd = request.data.get('pswd')  
        user = User.objects.filter(name=name, pswd=pswd).first()  
        # 如果用户存在  
        if user:  
            token = str(uuid.uuid4())  
            user_token = Token.objects.filter(user=user).first()  
            # if user_token:  
            # user_token.token = token  
            # user_token.save()  
            # else:  
            # Token.objects.create(user=user, token=token)  

            # 新用法  
            Token.objects.update_or_create(defaults={'token':token}, user=user)  
            return Response({'code':200, 'msg':'登录成功!', 'token':token, '用户名':name})  
        else:  
            return Response({'code':1001, 'msg':'用户名或者密码错误'})

第二种方法:

class UserView(ModelViewSet):  
  
    queryset = User.objects.all()  
    serializer_class = UserSerializer  

    @action(methods=['POST'], detail=False, url_path='login')  
    def login(self, request, *args, **kwargs):  
        user = self.get_queryset().filter(name=request.data.get('name'), pswd=request.data.get('pswd')).first()  
        if user:  
            token = str(uuid.uuid4())  
            Token.objects.update_or_create(defaults={'token':token}, user=user)  
            return Response({'code':200, 'msg':'登录成功!', 'token':token, '用户名':request.data.get('name')})  
        else:  
            return Response({'code':1001, 'msg':'用户名或者密码错误'})

update_or_create 源码

deafult是详情(字典类型), **kwargs是字段

def update_or_create(self, defaults=None, **kwargs):  
    """  
    Look up an object with the given kwargs, updating one with defaults  
    if it exists, otherwise create a new one.  
    Return a tuple (object, created), where created is a boolean  
    specifying whether an object was created.  
    """  
    
    defaults = defaults or {}  
    self._for_write = True  
    with transaction.atomic(using=self.db):  
    # Lock the row so that a concurrent update is blocked until  
    # update_or_create() has performed its save.  
    obj, created = self.select_for_update().get_or_create(defaults, **kwargs)  
    if created:  
        return obj, created  
    for k, v in resolve_callables(defaults):  
        setattr(obj, k, v)  
        obj.save(using=self.db)  
    return obj, False

认证组件

认证有什么作用

给一些接口添加认证。限制登录访问,登录后可以访问,没有登录不可以访问

具体操作步骤

当前举例实在请求地址中添加的token

  1. 写一个类,继承BaseAuthentication

from rest_framework.authentication import BaseAuthentication

from rest_framework.exceptions import AuthenticationFailed

from app01.models import Token

  1. 类中重写authenticate
class LoginAuth(BaseAuthentication):  
  
    def authenticate(self, request):  
        # 通过token校验,在请求地址中拿到token  
        token = request.query_params.get('token')  
        # token = request.META.get("HTTP_AUTHORIZATION")  
        print(token)  
        user_token = Token.objects.filter(token=token).first()  
        if user_token:  
            return Token.user, token  
        else:  
            raise AuthenticationFailed('用户没有登录')
  1. 在authenticate中完成登录认证,如果登录了返回两个值,如果没有登录抛异常

  2. 在视图类中配合使用

class BookView(ModelViewSet):  

    authentication_classes = [LoginAuth]  

    def list(self, request):  
        print(request.query_params.get('token'))  
        # print(request.META.get("HTTP_AUTHORIZATION"))  
        return Response('ok')

如果登录了,可以拿到登录的用户信息,因为我们在auth.py里面return出去了user

其他添加token的办法

Express: var token = req.header("Authorization").split(" ")[1];

Django: token = request.META.get("HTTP_AUTHORIZATION")

Flas: token = request.headers.get("Authorization")

配置文件中的全局配置

在setting.py里面

REST_FRAMEWORK = {  
    'DEFAULT_AUTHENTICATION_CLASSES':[  
        'app01.auth.LoginAuth'  
    ],  
}

权限组件

目的

系统中有普通用户,VIP用户,SVIP用户,超级管理员。这些用户都登录了,但是要给他们分权限,有的人有权限,有的人可以访问这个接口。没有权限就不能访问。这样的话,我们首先就要在我们的user表里面添加一个字段(用户等级)

代码

from rest_framework.permissions import BasePermission  
  
'''  
1. 写一个类,继承BasePermission  
2. 重写has_permission  
3. 在方法中校验用户是否有权限,如果有,就返回True,如果没有就抛异常  
'''  
  
class UserPerimission(BasePermission):  
    def has_permission(self, request, view):  
    # request 是当次请求的request(新的,同样也是在认证后执行的)如果认证通过了,request.user就是当前登录用户  
    # 拿到当前登录用户,查看它的类型,确实有没有权限  
    print(request.user)  
    if request.user.vip == 3:  
        return True  
    else:  
        return False

配置文件中的全局配置

REST_FRAMEWORK = {  

    'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.UserPerimission',],  
}

频率组件

目的

控制一个接口的访问频次,比如一分钟只能访问一次。我们为了预防爬虫和其他对程序的损害,我们应该对所有接口都有频率限制。

代码

from rest_framework.throttling import SimpleRateThrottle  
  
'''  
1. 写一个类,继承SimpleRateThrottle  
2. 重写get_cache_key,返回什么就以什么做限制:IP地址,用户id限制  
3. 写一个类属性 scope = ' '  
4. 配置文件中配置  
'''  
  
class IPRateThrottle(SimpleRateThrottle):  

    scope = 'HW0906' # 写一个类属性  

    def get_cache_key(self, request, view):  
        print(request.user.name)  
        # 返回IP,以IP地址做限制  
        # print(request.META)  
        # return request.META.get('REMOTE_ADDR')  
        return request.user.name

全局配置


REST_FRAMEWORK = {  
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.auth.LoginAuth'],  
  
'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.UserPerimission',],  
  
'DEFAULT_THROTTLE_RATES': {'HW0906':'3/m'}, # 一分钟访问3次  
  
'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.IPRateThrottle'],  
}