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文件中配置的----->最后取默认配置
Django之REST_FRAMEWORK 认证组件的更多相关文章
- Django的rest_framework认证组件之全局设置源码解析
前言: 在我的上一篇博客我介绍了一下单独为某条url设置认证,但是如果我们想对所有的url设置认证,该怎么做呢?我们这篇博客就是给大家介绍一下在Rest_framework中如何实现全局的设置认证组件 ...
- Django的rest_framework认证组件之局部设置源码解析
前言: Django的rest_framework组件的功能很强大,今天来我来给大家剖析一下认证组件 下面进入正文分析,我们从视图开始,一步一步来剖析认证组件 1.进入urls文件 url(r'^lo ...
- django的forms认证组件
django的forms认证组件 每个网站的注册界面都需要有相应的"认证"功能,比如说认证注册页面的用户名是否已被注册,二次输入的密码是否一致以及认证用户输入的用户名.邮箱.手机号 ...
- python 全栈开发,Day79(Django的用户认证组件,分页器)
一.Django的用户认证组件 用户认证 auth模块 在进行用户登陆验证的时候,如果是自己写代码,就必须要先查询数据库,看用户输入的用户名是否存在于数据库中: 如果用户存在于数据库中,然后再验证用户 ...
- rest_framework -- 认证组件
#####认证组件##### 一.认证是什么就不说了,某些网页必须是用户登陆之后,才能访问的,所以这时候就需要用上认证组件. 你不用rest_framework的认证组件也行,这种认证的话,完全可以自 ...
- Django REST framework —— 认证组件源码分析
我在前面的博客里已经讲过了,我们一般编写API的时候用的方式 class CoursesView(ViewSetMixin,APIView): pass 这种方式的有点是,灵活性比较大,可以根据自己的 ...
- rest_framework 认证组件 权限组件
认证组件 权限组件 一.准备内容 # models class User(models.Model): name = models.CharField(max_length=32) pwd = mod ...
- django - 总结 - 用户认证组件
用户认证组件 from django.contrib import auth 从auth_user表中获取对象,没有返回None,其中密码为密文,使用了加密算法 user = auth.authent ...
- django的用户认证组件
DataSource:https://www.cnblogs.com/yuanchenqi/articles/9064397.html 代码总结: 用户认证组件: 功能:用session记录登录验证状 ...
随机推荐
- NOIP2013-2014提高组题目浅析
1.前言 迎接NOIP的到来...在这段闲暇时间,决定刷刷水题.这里只是作非常简单的一些总结. 2.NOIP2014 <1> 生活大爆炸之石头剪刀布(模拟) 这是一道考你会不会编程的题目. ...
- 关于三层架构和MVC模式的思考
MVC模式 核心: 1.解耦Model和View,即使得Model可以被不同的展示,比如一批统计数据可以分别用柱状图.饼图表示 2.Controller用来保证Model和View的同步 Model ...
- pytest 打印调试信息
pytest_lean2.py #coding=utf- import pytest import os import sys import time import json sys.path.app ...
- 通过rpm安装crontab
可以在对应的虚拟机centos上查看 所安装的crontab安装信息,然后选中rpm包进行安装,命令:rpm -qa |grep cron 如: 如没有上述信息,表名没有安装,也可以直接用cronta ...
- 你的ThreadLocal线程安全么
想必很多小伙伴们对ThreadLocal并不陌生,ThreadLocal叫做线程本地变量,也就是ThreadLocal为变量在每个线程中都创建了一个副本,每个线程可以访问自己内部的副本变量.那么,我们 ...
- leetcode 13. Integer to Roman
使用eval,特别处理6个case var romanToInt = function (s) { const map = { 'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C ...
- docker nginx-php容器镜像瘦身优化
1. 在安装好php环境的容器,参考上面贴出的链接那篇文章的部分,做好基础工作: #创建工作目录 mkdir /rootfs #进入工作目录 cd /rootfs #创建基础目录 mkdir -p b ...
- c# winform richtextbox控制每行颜色 + 滚动条始终滚动到最底部
/// <summary> /// 输出 /// </summary> /// <param name="content"></param ...
- [.Net,C#]三类资源:流对象Stream,字节数组byte[],图片Image
三类资源:流对象Stream,字节数组byte[],图片Image 关系:Stream<=>byte[],byte[]<=>Image Stream 与Image相互转化的媒介 ...
- 一台Linux服务器(4C8G配置)可以负载百万个连接?
一台Linux服务器可以负载多少个连接? 首先我们来看如何标识一个TCP连接?系统是通过一个四元组来识别,(src_ip,src_port,dst_ip,dst_port)即源IP.源端口.目标IP. ...