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文件中配置的----->最后取默认配置

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

  1. Django的rest_framework认证组件之全局设置源码解析

    前言: 在我的上一篇博客我介绍了一下单独为某条url设置认证,但是如果我们想对所有的url设置认证,该怎么做呢?我们这篇博客就是给大家介绍一下在Rest_framework中如何实现全局的设置认证组件 ...

  2. Django的rest_framework认证组件之局部设置源码解析

    前言: Django的rest_framework组件的功能很强大,今天来我来给大家剖析一下认证组件 下面进入正文分析,我们从视图开始,一步一步来剖析认证组件 1.进入urls文件 url(r'^lo ...

  3. django的forms认证组件

    django的forms认证组件 每个网站的注册界面都需要有相应的"认证"功能,比如说认证注册页面的用户名是否已被注册,二次输入的密码是否一致以及认证用户输入的用户名.邮箱.手机号 ...

  4. python 全栈开发,Day79(Django的用户认证组件,分页器)

    一.Django的用户认证组件 用户认证 auth模块 在进行用户登陆验证的时候,如果是自己写代码,就必须要先查询数据库,看用户输入的用户名是否存在于数据库中: 如果用户存在于数据库中,然后再验证用户 ...

  5. rest_framework -- 认证组件

    #####认证组件##### 一.认证是什么就不说了,某些网页必须是用户登陆之后,才能访问的,所以这时候就需要用上认证组件. 你不用rest_framework的认证组件也行,这种认证的话,完全可以自 ...

  6. Django REST framework —— 认证组件源码分析

    我在前面的博客里已经讲过了,我们一般编写API的时候用的方式 class CoursesView(ViewSetMixin,APIView): pass 这种方式的有点是,灵活性比较大,可以根据自己的 ...

  7. rest_framework 认证组件 权限组件

    认证组件 权限组件 一.准备内容 # models class User(models.Model): name = models.CharField(max_length=32) pwd = mod ...

  8. django - 总结 - 用户认证组件

    用户认证组件 from django.contrib import auth 从auth_user表中获取对象,没有返回None,其中密码为密文,使用了加密算法 user = auth.authent ...

  9. django的用户认证组件

    DataSource:https://www.cnblogs.com/yuanchenqi/articles/9064397.html 代码总结: 用户认证组件: 功能:用session记录登录验证状 ...

随机推荐

  1. Glimma 包

    http://master.bioconductor.org/packages/3.9/bioc/html/Glimma.html 安装 if (!requireNamespace("Bio ...

  2. concurrent(四)Condition

    参考文档:Java多线程系列--“JUC锁”06之 Condition条件:http://www.cnblogs.com/skywang12345/p/3496716.html Condition介绍 ...

  3. Notepad++ 【自动完成】与【输入时提示函数参数】互相冲突,无奈

    Notepad++ 既然可以在输入时提示函数参数,可是当提示函数参数的时候,输入具体参数时[自动完成]失效了. 一位用户遇到和我一样的问题:https://community.notepad-plus ...

  4. c#比较器辅助类

    /// <summary> /// 比较器帮助类 /// 创建人:苏本东 :: /// </summary> public class ComparerHelper<T& ...

  5. 一场Math.Round函数的误解

    有不少人误将Math.Round函数当作四舍五入函数在处理, 结果往往不正确, 实际上Math.Round采用的是国际通行的是 Banker 舍入法. Banker's rounding(银行家舍入) ...

  6. 蚂蚁花呗5面面试真题,你敢来挑战一下吗?(Java岗)

    蚂蚁花呗一面(一个小时): JDK 中有哪几个线程池?顺带把线程池讲了个遍 Java容器有哪些?哪些是同步容器,哪些是并发容器? ArrayList和LinkedList的插入和访问的时间复杂度? j ...

  7. java自带的xml解析工具类

    public class JaxbUtil { /** * java对象转换为xml文件 * * @param xmlPath xml文件路径 * @param load java对象.Class * ...

  8. KAFKA 节点配置问题

    -- ::, INFO o.a.j.e.StandardJMeterEngine: Running the test! -- ::, INFO o.a.j.s.SampleEvent: List of ...

  9. idea 本地调试,修改代码,代码自动生效

    修改1: 修改2: ctrl+shift+a 弹出页面中搜索“registry” 修改3:修改configerations

  10. Java学习:等待唤醒机制

    等待唤醒机制 线程的状态 NEW   至今尚未启动的线程处于这种状态 RUNNABLE   正在Java虚拟机中执行的线程处于这种状态 BLOCKED 受阻塞并等待某个监视器锁的线程处于这种状态 WA ...