Django:RestFramework之-------认证
3 restframework-认证
3.1APIView 认证:
- 认证是否已经登陆,如果已经登陆返回元组,如果没有登陆报错
- 源码流程:
执行dispatch方法:
def dispatch(self, request, *args, **kwargs):
#1.封装request 对原生request进行加工,执行initialize_request方法
request = self.initialize_request(request, *args, **kwargs)
try:
#2.认证
self.initial(request, *args, **kwargs)
#--------------------initialize_request-------------------
#执行initialize_request:
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
#返回实例化Request,把原有的request进行封装,丰富功能
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
#---------------------------------------------------------
#--------------------Request------------------------------
#而Request类中:实例化方法中定义:
class Request:
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
assert isinstance(request, HttpRequest), (
'The `request` argument must be an instance of '
'`django.http.HttpRequest`, not `{}.{}`.'
.format(request.__class__.__module__, request.__class__.__name__)
)
self._request = request#1
self.parsers = parsers or ()
self.authenticators = authenticators or ()#
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty
#1 : 获取原生request 通过 request._request
#2 : 获取认证类的对象 通过 request.authenticators
#返回dispatch方法中继续走
#---------------------------------------------------------
#--------------------initial----------------------------
#再initial执行方法:
def initial(self, request, *args, **kwargs):
...
#4.实现认证
self.perform_authentication(request)
#---------------------------------------------------------
#--------------------perform_authentication---------------
#返回当前登陆用户,此时request为封装加工后的request
def perform_authentication(self, request):
request.user
#---------------------------------------------------------
#---------------------------Request----------------------
#执行request为Request类中实例化的对象,通过.user执行user方法
class Request:
...
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
#获取认证对象,进行一步步认证
self._authenticate()
return self._user
#---------------------------------------------------------
#----------------_authenticate-------------------------
def _authenticate(self):
#authentication_classes=[BasicAuthentication对象,]
#authenticators为定义authentication_classes=中的对象
#循环所有认证对象。
for authenticator in self.authenticators:
try:
#通过authenticate方法验证是否登陆,如果登陆返回元组,如果未登陆报错
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
#---------------------------------------------------------
#-------------------------authenticate-----------------------------
def authenticate(self, request):
return (self.force_user, self.force_token)
- 那么如何自己定义认证:
import json
from django.http import HttpResponse
from django.shortcuts import render
from rest_framework.decorators import authentication_classes#用于自定义实现认证
from rest_framework.views import APIView
from rest_framework import exceptions#用于认证失败引发错误
class MyAuthentication(object):
#重写authenticate方法
def authenticate(self,request):
token = request._request.GET.get('token')
print(token)
if not token:
raise exceptions.AuthenticationFailed("用户认证失败")
return ("hello",None)
def authenticate_header(self,val):pass
class DogView(APIView):
#自定义认证类
authentication_classes = [MyAuthentication,]
def get(self,request,*args,**kwargs):
ret = {
"code":1000,
'msg':"OK"
}
return HttpResponse(json.dumps(ret),status=200)
def post(self,request,*args,**kwargs):
return HttpResponse("创建Dog")
#www.xxx.com/?token=123
效果:
- 当访问URL为
<http://127.0.0.1:8000/dog/
- 当访问URL为
<http://127.0.0.1:8000/dog/?token=123>
- 当访问URL为
基于认证总结:
源码流程 dispatch开始
3.2 用户登陆
models.py
class UserInfo(models.Model):
user_type_choice = {
(1,"普通用户"),
(2,"VIP"),
(3,"SVIP")
} user_type = models.IntegerField(choices=user_type_choice)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=32) class UserToken(models.Model):
user = models.OneToOneField(to="UserInfo")
token = models.CharField(max_length=32)
views.py
def md5(user):
"""密码加密"""
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user,encoding='utf-8'))
m.update(bytes(ctime,encoding="utf-8"))
return m.hexdigest()
class AuthView(APIView):
def post(self,request,*args,**kwargs):
ret = {"code":1000,"msg":None}
try:
username = request._request.POST.get('username')
password = request._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=username,password=password).first()
if not obj:
ret["code"] = 1001
ret["msg"] = "用户密码错误"
#为登陆用户创建token
token = md5(username)
#存在更新,不存在创建,保存Token
models.UserToken.objects.update_or_create(user=obj,defaults={"token":token})
except Exception as e:
ret["code"] = 1002
ret["msg"] = "请求异常"
return JsonResponse(ret)
3.3用户登陆实现token认证
#充当数据库数据
ORDER_DICT = {
1: {
'name': '媳妇',
'age': 18,
'gender': '男',
'content': '...'
},
2: {
'name': '老狗',
'age': 19,
'gender': '男',
'content': '....'
}
}
#自定义认证类
class Authtication(object):
def authenticate(self,request):
token = request._request.GET.get("token")
token_obj = models.UserToken.objects.filter(token=token).first()
#如果token表示用户认证失败
if not token_obj:
raise exceptions.AuthenticationFailed("用户认证失败")
#在restframework内部会将这两个字段赋值给request,以供后续使用
#第一个值通过request.user可以获取
#第二个值通过reuqest.auth可以获取
return (token_obj.user,token_obj)
def authenticate_header(self, val): pass
class OrderView(APIView):
authentication_classes = [Authtication,]
def get(self,request,*args,**kwargs):
# token = request._request.GET.get("token")
# if not token:
# return HttpResponse("用户未登陆")
ret = {"code": 1000, "msg": None, "data": None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
#通过restframework让视图函数只做数据处理,认证交给authentication_classes,代码逻辑清晰不少。
3.4认证流程原理
drf认证组件的实现过程:
as_view() --->view --->执行dispatch方法,
为自己dispatch方法。通过initialize_request将request对象进行了重新封装。通过initial执行perform_authentication,Request执行user方法去执行_authenticate,遍历循环authentication_classes所有对象。执行认证类的方法.
有三种情况:
1.如果有返回值,是一个元组 request.user,request.auth
2.如果返回None,下一个认证来处理:
当都返回None:request.user = AnonymousUser, request.auth = None
3.抛出异常,执行self.not_authenticated()当都返回None, request.user = AnonymousUser, request.auth = None.(设置默认值,表示未登陆)
源码中 全局使用配置项:
将自己定义认证类配置在rest_framework配置项目中
#当前项目新建文件夹,新建py文件,放入认证类
settings.py配置
REST_FRAMEWORK = {
#全局使用认证类。
'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.Authtication',],
#设置匿名用户None。
'UNAUTHENTICATED_USER':None,#request.user = None
'UNAUTHENTICATED_TOKEN':None,#当前用户未登陆表示匿名用户 request.auth = None
} #这样类视图都不用加authentication_classes,也可以执行认证。对于不需要认证的类视图,可以添加未 authentication_classes = []
3.5 django内置认证类
- 如下:5个类:
class BaseAuthentication:
class BasicAuthentication(BaseAuthentication):#通过浏览器生成登陆模态框,实现base64加密,把加密后信息放在请求头发过去。
class SessionAuthentication(BaseAuthentication):
class TokenAuthentication(BaseAuthentication):
class RemoteUserAuthentication(BaseAuthentication):
- 为了让我们写认证类,更加规范,自定义认证类都必须要继承于
BaseAuthentication
class BaseAuthentication:
"""
All authentication classes should extend BaseAuthentication.
"""
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.")
def authenticate_header(self, request):
#当认证失败时候,浏览器给返回响应头
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
#所有定义认证类必须有authenticate,authenticate_header方法。否则无法正常执行代码
Django:RestFramework之-------认证的更多相关文章
- Django rest-framework框架-认证组件的简单实例
第一版 : 自己写函数实现用户认证 #models from django.db import models #用户表 class UserInfo(models.Model): user_type_ ...
- django restframework
一.django restframework 请求流程源码剖析 上面的认证一个流程是rest_framework的关于APIauth的认证流程,,这个流程试用权限.频率.版本.认证.这个四个组件都是通 ...
- django restframework jwt
既然要来学习jwt(json web token),那么我们肯定是先要了解jwt的优势以及应用场景--跨域认证. $ pip install djangorestframework-jwt 传统coo ...
- Django Restframework 实践(一)
具备以下知识: django http://www.cnblogs.com/menkeyi/p/5882464.html http://www.cnblogs.com/menkeyi/p/588245 ...
- django restframework 的日常使用
本文讨论 django restframework 的日常使用,满足常用 api 编写的需求,比如 List, Detail, Update, Put, Patch 等等.探讨 django rest ...
- Django RestFramework (DRF)
准备: 下载 pip install djangorestframework 一 APIView源码解析 1 预备知识 CBV(class based view)FBV(function based ...
- django restframework serializer 增加自定义字段
在使用django restframework serializer 序列化在django中定义的model时,有时候我们需要额外在serializer中增加一些model中没有的字段.有两种方法实现 ...
- Django组件之认证系统
Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Dja ...
- Django Rest Framework(认证、权限、限制访问频率)
阅读原文Django Rest Framework(认证.权限.限制访问频率) django_rest_framework doc django_redis cache doc
随机推荐
- Codeforces Round #609 (Div. 2) A到C题
签到,乘以两个相邻的合数 #include<bits/stdc++.h> using namespace std; int main(int argc, char const *argv[ ...
- 08-cmake语法-set()
CMake的基本数据类型是字符串,一组字符串在一起称为列表(list) 用于设置变量. set(VAR a b c) # 输出 VAR = a;b;c VAR 就是一个list 参考: https:/ ...
- HBaseAPI
环境准备 新建项目后在pom.xml中添加依赖: <dependency> <groupId>org.apache.hbase</groupId> <arti ...
- 爬虫-selenium的使用
安装 pip install selenium 开始 # coding=utf-8 from selenium import webdriver # 引用selenium库 import time # ...
- Game Publisher
“Amazon Appstore https://developer.amazon.com/why-amazonApple Store https://developer.apple.com/prog ...
- 微信小程序 组件 全局样式
配置如下设置 /** * 组件的一些选项 */ options: { addGlobalClass: true },
- Pandas | 23 分类数据
通常实时的数据包括重复的文本列.例如:性别,国家和代码等特征总是重复的.这些是分类数据的例子. 分类变量只能采用有限的数量,而且通常是固定的数量.除了固定长度,分类数据可能有顺序,但不能执行数字操作. ...
- 使用uwsgi+nginx部署项目
Uwsgi:部署web应用程序 Nginx:反向代理,静态服务器 1.修改uwsgi配置文件>nginx反向代理[nginx接收请求->传递->[uwsgi] http=.. --& ...
- 渗透测试工具Nmap篇
Nmap是一款网络扫描和主机检测的非常有用的工具. Nmap是不局限于仅仅收集信息和枚举,同时可以用来作为一个漏洞探测器或安全扫描器.它可以适用于winodws,linux,mac等操作系统.Nmap ...
- bind 安装 和配置(master/slave)
一,软件安装 #sudo yum -y install bind 二,配置 # vi /etc/named.conf // // named.conf // // Provided by Red H ...