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. c# Aes加解密

    using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; ...

  2. day 19

    If you think you can, you can. And if you think you can't, you're right.

  3. PATA1012The Best Rank(25分)

    To evaluate the performance of our first year CS majored students, we consider their grades of three ...

  4. Perl 使用perl命令批量替换文件内容

    对linux系统下面多个文本文件内容做处理,是SA经常需要完成的工作.如何高效的完成这个工作,perl应该是一个不错的语言工具.你甚至不需要编写perl脚本,用命令就可以完成上面的工作. perl 命 ...

  5. 安装-apache skywalking (java 应用性能监控)

    官网:http://skywalking.apache.org/ 服务器:10.30.31.28 centos 7 jdk 1.8.x ES 5.x 5.0.0-bet a2版本 . http://s ...

  6. 一个sh脚本 同时运行 多个sh脚本

    问题: 原来的启动方式 cd /opt/OpenIMSCore ./pcscf.sh ./icscf.sh ./scscf.sh cd /opt/OpenIMSCore/FHoSS/deploy ./ ...

  7. URL中出现了%E2%80%8E(Zero-Width Space)

    下面两个url地址,看起来是一样的,但是粘贴到记事本里会发现一个多出了很长的空格 url: '/secure​/Dishes/GetList', url: '/secure/Dishes/GetLis ...

  8. 在C++中调用FFTW

    FFTW是一个可以进行可变长度一维或多维DFT的开源C程序库,是目前最快的FFT算法实现. 本文简述了在Windows平台上,如何在C++中调用FFTW,所使用的IDE为Visual Studio 2 ...

  9. DRF框架和Vue框架阅读目录

    Vue框架目录 (一)Vue框架(一)——Vue导读.Vue实例(挂载点el.数据data.过滤器filters).Vue指令(文本指令v-text.事件指令v-on.属性指令v-bind.表单指令v ...

  10. TJOI2018简要题解

    Day1T1数学计算 按照时间轴建一棵线段树即可,复杂度为\(O(m \log m)\) #include <bits/stdc++.h> #define N 100005 #define ...