Django authentication component of REST_FRAMEWORK

DRF of Django's authentication component

# from rest_framework.views import APIView
# APIView 中的  dispatch  中 执行的  self.initial(request,*args,**kwargs)中的 
# APIView---->dispatch------>self.initial------>三个校验
        # self.perform_authentication(request)  # 认证校验
        # self.check_permissions(request)  # 权限校验
        # self.check_throttles(request)  # 频率校验
# 这里的self 指的是我写的那个序列化类

    def perform_authentication(self, request):
        # 这里的request 是新的request  原生的request 在   新request._request 中
        """
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        """
        # 返回的user 是 新的request 中的一个 被伪装成属性的方法(@property)
        # 想要超看这个 需要导包  from rest_frmework.request import Request
        request.user

    def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

Here the user belongs method:

from rest_framework.request import Request
# Request类中--->user方法----->里面执行了  _authenticate(self) 方法

Is disguised as attribute data,

@property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                # 这里的self 是 Request 对象
                self._authenticate()  # 这里执行的是 Request 类中的_authenticate()
        return self._user

Focus on the logic of this code is as follows:

    # APIView-->dispatch--->self.initial--->self.perform_authentication(request)
    # --->reuqest.user---->self._authenticate
    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        尝试依次使用每个身份验证实例对请求进行身份验证。
        """
        # 这里的 self.autenticators 是一个元组,里面存的是一个个实例化的对象
        # 这里元组 是 Request 类在实例化的时候执行 __init__方法的时候赋值来的
        for authenticator in self.authenticators:
            try:
                # 这里是执行自己写的认证类中的的 authenticate()方法,得到的是一个元组(这里面存的是 user对象  和 一个auth对象)!!!如果有返回值的话
                user_auth_tuple = authenticator.authenticate(self)
                # 如果该方法中返回 user对象 和 auth对象 
            except exceptions.APIException:
                self._not_authenticated()  # 如果没有通过认证走这个方法
                raise
           # 如果user_auth_tuple 有值,不为空
            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

The use of certified components

models.py

from django.db import models


# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateTimeField(auto_now_add=True)  # 自动添加创建时间
    authors = models.ManyToManyField('Author')
    publish = models.ForeignKey('Publish')  # 一对多
    
    def test(self):
        return self.title+'>>'+str(self.price)


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    authordetail = models.OneToOneField('AuthorDetail')


class AuthorDetail(models.Model):
    tel_num = models.BigIntegerField()
    addr = models.CharField(max_length=32)


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

# 用户类
class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
# token类 与用户类一对一关系
class Token(models.Model):
    user = models.OneToOneField(to='User')
    token = models.CharField(max_length=64)

Establishment (usually a new py file) certification class

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

class MyAuth(BaseAuthentication):
    # 在认证组件中  需要重写 authenticate方法来 完成 用户认证逻辑
    def authenticate(self, request):
        # request值得是个对象
        token = request.GET.get('token')
        token_obj = models.Token.objects.filter(token=token).first()
        if token_obj:
            # 有值表示登录了
            return
        else:
            # 没有值,则报错
            raise AuthenticationFailed('您没有登录')

views.py

from django.shortcuts import render
from django.http.response import JsonResponse

# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.myser import BookSerializer
from app01 import auths
from django.core.exceptions import ObjectDoesNotExist
import uuid




class Book(APIView):
    # 这里固定 需要些 这个认证类的列表,列表中存的是 一个一个认证的类
    authentication_classes = [auths.MyAuth,]
    # get 获取所有书籍信息
    def get(self, request, id):
        response = {'status': 100, 'msg': '成功'}
        print(id)
        if not id:
            book_list = models.Book.objects.all()
            # 第一个参数是要序列化的queryset对象,如果要序列化多条,必须制定many=True
            # 当instance形参被传入的实参是单个参数的时候,many=False
            book_serializer = BookSerializer(book_list, many=True)
        else:
            print(id)
            book_obj = models.Book.objects.filter(pk=id).first()
            book_serializer = BookSerializer(book_obj, many=False)
        print(book_serializer.data)
        response['books'] = book_serializer.data
        return Response(response)
    
    def post(self, request, id):
        response = {'status': 100, 'msg': '成功'}
        # 提交的字典
        book = request.data
        # 传统方法,创建对象保存
        print(book)
        
        # 新方法,通过序列化组件保存,必须继承自ModelSerializer
        book_ser = BookSerializer(data=book)
        # is_valid 提交的字段校验通过
        if book_ser.is_valid():
            book_ser.save()
            response['book'] = book_ser.data
        else:
            response['msg'] = book_ser.errors  # errors  是序列化类 中的钩子函数 raise来的报错信息
        return Response(response)
    
    def put(self, request, id):
        response = {'status': 100, 'msg': '修改成功'}
        if id:
            
            # 提交的字典
            book = request.data
            # 传统方法,创建对象保存
            print(book)
            book_obj = models.Book.objects.filter(pk=id).first()
            
            # 新方法,通过序列化组件保存,必须继承自ModelSerializer
            book_ser = BookSerializer(data=book, instance=book_obj)
            # is_valid 提交的字段校验通过
            if book_ser.is_valid():
                # 这里save()做修改
                book_ser.save()
                response['book'] = book_ser.data
            else:
                response['msg'] = book_ser.errors
        else:
            response['msg'] = '修改对象不存在'
        return Response(response)
    
    def delete(self, request, id):
        models.Book.objects.filter(pk=id).delete()
        response = {'status': 100, 'msg': '删除成功'}
        return Response(response)

class Login(APIView):
    # 局部禁用 认证
    authentication_classes = []
    def post(self, request):
        response = {'code': 100, 'msg': '登录成功'}
        name = request.data.get('name')
        pwd = request.data.get('pwd')
        print(name, pwd)
        try:
            # get()方法,获取 有且只有一条的 才不报错,其他情况都抛异常
            ret = models.User.objects.filter(name=name, pwd=pwd).get()
            
            # 登录成功后要去token 表中去存数据
            # 表里有 数据或没有数据
            # 1. 先生成随机字符串 用uuid
            token = uuid.uuid4()
            # 2. 存入token表
            # update_or_create()  方法  先查后改,查到就修改,没查到就新增  根据  user 去查
            models.Token.objects.update_or_create(user=ret, defaults={'token': token})
            response['token'] = token
        except ObjectDoesNotExist as exc:
            response['code'] = 101
            response['msg'] = '用户名或密码错误'
        except Exception as e:
            response['code'] = 102
            response['msg'] = str(e)
        return Response(response)

Authentication token does not exist

def get_token(id,salt='123'):
    import hashlib
    md=hashlib.md5()
    md.update(bytes(str(id),encoding='utf-8'))
    md.update(bytes(salt,encoding='utf-8'))

    return md.hexdigest()+'|'+str(id)

def check_token(token,salt='123'):
    ll=token.split('|')
    import hashlib
    md=hashlib.md5()
    md.update(bytes(ll[-1],encoding='utf-8'))
    md.update(bytes(salt,encoding='utf-8'))
    if ll[0]==md.hexdigest():
        return True
    else:
        return False

class TokenAuth():
    def authenticate(self, request):
        token = request.GET.get('token')
        success=check_token(token)
        if success:
            return
        else:
            raise AuthenticationFailed('认证失败')
    def authenticate_header(self,request):
        pass
class Login(APIView):
    def post(self,reuquest):
        back_msg={'status':1001,'msg':None}
        try:
            name=reuquest.data.get('name')
            pwd=reuquest.data.get('pwd')
            user=models.User.objects.filter(username=name,password=pwd).first()
            if user:
                token=get_token(user.pk)
                # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                back_msg['status']='1000'
                back_msg['msg']='登录成功'
                back_msg['token']=token
            else:
                back_msg['msg'] = '用户名或密码错误'
        except Exception as e:
            back_msg['msg']=str(e)
        return Response(back_msg)
from rest_framework.authentication import BaseAuthentication
class TokenAuth():
    def authenticate(self, request):
        token = request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if token_obj:
            return
        else:
            raise AuthenticationFailed('认证失败')
    def authenticate_header(self,request):
        pass

class Course(APIView):
    authentication_classes = [TokenAuth, ]

    def get(self, request):
        return HttpResponse('get')

    def post(self, request):
        return HttpResponse('post')

to sum up:

  • Local use: as long as the required certification class what is written inside a fixed certification (certification class) you need

     # 这里固定 需要些 这个认证类的列表,列表中存的是 一个一个认证的类
        authentication_classes = [auths.MyAuth,]
  • Global use: as long as the settings in the configuration file can be REST_FRAMEWORK

    # settings.py 中配置
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auths.MyAuth", ]
    }
  • Local Disabled: As long as you do not need to clear authentication_classes certification in the view class do not need to use global authentication can be used in

    authentication_classes=[]

Read Source experience:

  • If you configure REST_FRAMEWORK in settings.py file, taken from the first default in the project settings
  • If you did not get before going to the default configuration file to take drf
  • If the user authentication_classes disposed in the view class, the user is taken from the priority allocation

ps: first take-certified configuration view class ---> then take the project settings configuration file -----> finally take the default configuration

Guess you like

Origin www.cnblogs.com/qianzhengkai/p/11129867.html