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. 【BZOJ3508】开灯

    [BZOJ3508]开灯 题面 bzoj 题解 其实变为目标操作和从目标操作变回来没有区别,我们考虑从目标操作变回来. 区间整体翻转(\(\text{Xor}\;1\))有点难受,我们考虑将这个操作放 ...

  2. 配置Nginx的防盗链

    实验环境 一台最小化安装的CentOS 7.3虚拟机 配置:1核心/512MB nginx版本1.12.2 一.配置盗链网站 1.启动一台nginx虚拟机,配置两个网站 vim /etc/nginx/ ...

  3. Burp Suite 入门教程(BURP SUITE TUTORIAL )

    参考链接1:https://www.pentestgeek.com/what-is-burpsuite 参考链接2:https://www.pentestgeek.com/web-applicatio ...

  4. windows下SVN使用 Add指令、Undo Add指令

    前几天,使用SVN的Add指令添加了一个文件,后不使用直接删除了,每次提交都存在,解决后记录方法,希望帮到大家,此外如果大家有好的方法,希望可以回复. 问题:使用Add添加文件后直接删除了文件,每次提 ...

  5. Appium+iOS真机环境搭建

    安装目录 1.macOS系统  10.12.6 2.xcode  9.0 3.appium Desktop  1.12.1 4.node.js node -v npm 5.cnpm npm insta ...

  6. win10 .net framework 3.5 离线安装 不需要外网

    win 10如果安装系统时没有安装.net 3.5 那么在以后安装时就必须联网. win10 .net framework 3.5 离线安装工具: 链接: https://pan.baidu.com/ ...

  7. 第十七节:.Net Core中新增HttpClientFactory的前世今生

    一. 背景 1.前世 提到HttpClient,在传统的.Net版本中简直臭名昭著,因为我们安装官方用法 using(var httpClient = new HttpClient()),当然可以Di ...

  8. Springboot Actuator之十一:actuator transaction

    前言spring boot 的自动化配置其实就是在spring 的基础上做的封装,在我们之前对mvc,aop的自动化配置中可以发现–> 只是在spring 的基础上添加了一些特性,可以认为只是一 ...

  9. 使用Fiddler抓包、wireshark抓包分析(三次握手、四次挥手深入理解)

    ==================Fiddler抓包================== Fiddler支持代理的功能,也就是说你所有的http请求都可以通过它来转发,Fiddler代理默认使用端口 ...

  10. Java 在 Word 文档中使用新文本替换指定文本

    创作一份文案,经常会高频率地使用某些词汇,如地名.人名.人物职位等,若表述有误,就需要整体撤换.文本将介绍如何使用Spire.Doc for Java,在Java程序中对Word文档中的指定文本进行替 ...