Django之REST_FRAMEWORK 认证组件

Django之DRF之认证组件

# 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)
                )

这里的user方法属于 :

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

是 被伪装成数据属性,

@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

重点的逻辑就是如下这段代码:

    # 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()

认证组件的使用

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)

认证类的建立(一般新建一个py文件)

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)

不存token的认证

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')

总结:

  • 局部使用: 只要在 需要认证的类里面 固定写入你所需的哪些认证(认证类)

     # 这里固定 需要些 这个认证类的列表,列表中存的是 一个一个认证的类
        authentication_classes = [auths.MyAuth,]
  • 全局使用: 只要在settings文件中配置 REST_FRAMEWORK 即可
    # settings.py 中配置
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auths.MyAuth", ]
    }
  • 局部禁用:只要在不需要使用全局使用的认证的 视图类中清除authentication_classes中你不需要的认证即可
    authentication_classes=[]

阅读源码体会:

  • 如果在settings.py 文件中配置了 REST_FRAMEWORK,先默认从项目settings中取
  • 如果取不到,才去默认的drf配置文件中取
  • 用户如果在 视图类中配置了authentication_classes, 则优先从用户配置的取

ps:先取视图类中的配置的认证--->再取 项目settings文件中配置的----->最后取默认配置

原文地址:https://www.cnblogs.com/qianzhengkai/p/11129867.html

时间: 2024-10-31 17:00:10

Django之REST_FRAMEWORK 认证组件的相关文章

Django之auth认证组件

原文链接:https://www.jianshu.com/p/612b3d76a1f5 Django之auth组件 前言:我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统. 此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点.它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据. auth中提供的实用方法: - 创建用户 pytho

Django Rest Framework 认证组件

'''用户认证章节''' # 用户认证章节:写一个数据接口 from django.http import JsonResponse from .utils import get_token from rest_framework.exceptions import APIException class UserView(APIView): def post(self, request): # 定义返回消息体 response = dict() # 定义需要的用户信息 fields = {"us

14 Django的用户认证组件

用户认证 auth模块 1 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1.1 .authenticate()    提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数 如果认证信息有效,会返回一个  User  对象.authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的

Django的用户认证组件

用户认证 (一)auth模块 1 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1.1 .authenticate()    提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数 如果认证信息有效,会返回一个  User  对象.authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是

django之用户认证组件

用户认证 auth模块 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1.authenticate() 提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数如果认证信息有效,会返回一个User对象.authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的.当我们试图登陆一个从数据

Django Rest Framework 认证组件(权限组件)

from rest_framework.viewsets import ModelViewSet from .authentication_classes import UserAuth from .permission_classes import UserPerm class BookView(ModelViewSet): # 在需要认证的数据接口里面指定认证类 authentication_classes = [UserAuth] # 在需要认证的数据接口里面指定权限类 permissio

django安全认证组件

创建超级用户的方法 第一步要先进行数据迁移,生成默认的auth_user表 1,python manager.py makemigrations 2, python manager.py migrate 第二步,创建超级用户,会存储在auth_user表中 python manager.py createsuperuser 执行完命令按照提示逐步完善信息,超级用户的密码会以md5加密的方式存储在auth_user表中,其他信息都是明文显示 django用户安全认证组件 1,引入模块 from d

002---rest_framework认证组件

rest_framework认证组件 问题:有些API,需要用户登录才能访问,有些无需登录就能访问. 解决: a. 创建两个模型类:UserInfo---OneToOne---UsetToken b. 登录成功后保存在数据库的UserToken表中 # urls.py from django.urls import path from api import views urlpatterns = [ path('api/v1/auth/',views.AuthView.as_view()), ]

Django中rest_framework的认证组件,权限组件,频率组件,序列化组件的最简化版接口

url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.Login.as_view()), # Book表 url(r'^books/$',views.BookHandle.as_view({ 'get':'list', 'post':'create' })), url(r'^books/(?P<pk>\d+)/',views.BookHandle.as_view({ 'get':'retrieve