自定义token认证

我们知道,在django项目中不管路由以及对应的视图类是如何写的,都会走到 dispatch 方法,进行路由分发,

在阅读 APIView类中的dispatch 方法的源码中,有个 self.initial(request, *args, **kwargs),可以发现认证、权限、频率这三个默认组件都在这个方法里面,如果我们自己没有定义这三个组件的配置,那么就会使用源码中默认的一些配置。

源码:

# Ensure that the incoming request is permitted

#实现认证
self.perform_authentication(request) #权限判断
self.check_permissions(request) #控制访问频率
elf.check_throttles(request)

目前为止大家知道的认证机制是不是有cookie、session啊,session更安全一些,但是你会发现session的信息都存到咱们的服务器上了,如果用户量很大的话,服务器压力是比较大的,并且django的session存到了django_session表中,不是很好操作,但是一般的场景都是没有啥问题的,现在生产中使用的一个叫做token机制的方式比较多,现在我们是不是就知道个csrf_token啊,其实token有很多种写法,如何加密,你是hashlib啊还是base64啊还是hmac啊等,是不是加上过期时间啊,是不是要加上一个secret_key(客户端与服务端协商好的一个字符串,作为双方的认证依据),是不是要持续刷新啊(有效时间要短,不断的更新token,如果在这么短的时间内还是被别人拿走了token,模拟了用户状态,那这个基本是没有办法的,但是你可以在网络或者网络设备中加安全,存客户的ip地址等,防黑客)等等。

大致流程图解:

      

    

首先我们需要创建一个表,用户表,里面放一个token字段,其实一般我都是放到两个表里面,和用户表是一个一对一关系的表,看代码:

models.py内容如下:

################################# user表 ###############################
class User(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
type_choice=((1,"VIP"),(2,"SVIP"),(3,"SSVIP"))
user_type = models.IntegerField(choices=type_choice) class UserToken(models.Model):
user = models.OneToOneField(to=User) #一对一到用户表
token = models.CharField(max_length=128) #设置的长度大一些
# expire_time = models.DateTimeField() #如果做超时时间限制,可以在这里加个字段

urls.py内容如下:

#登陆认证接口
url(r'^login/$', views.LoginView.as_view(),), #别忘了$符号结尾

   

views.py内容如下:每次登陆成功之后刷新token值

###################login逻辑接口#######################
#关于逻辑接口而不是提供数据的接口,我们不用ModelViewSet,而是直接写个类,继承APIView,然后在类里面直接写咱的逻辑 import uuid
import os
import json class LoginView(APIView): #从前后端分离的项目来讲,get请求不需要写,因为get就是个要登陆页面的操作,vue就搞定了,所以我们这里直接写post请求就可以了
def post(self,request):
# 一般,请求过来之后,我们后端做出的响应,都是个字典,不仅包含错误信息,还有要状态码等,让客户端明白到底发生了什么事情
# 'code'的值,1表示成功,0表示失败,2表示其他错误(自己可以做更细致的错误代码昂)
res = {'code': 1, 'msg': None, 'user': None,'token':None}
print(request.data)
try:
user = request.data.get('user')
pwd = request.data.get('pwd')
# 数据库中查询
user_obj = models.User.objects.filter(user=user, pwd=pwd).first()
if user_obj:
res['user'] = user_obj.user
# 添加token,用到咱们usertoken表
# models.UserToken.objects.create(user=user,token='123456')
# 创建token随机字符串,我写了两个方式,简写的昂,最好再加密一下
random_str = uuid.uuid4()
# random_str = os.urandom(16) bytes类型的16位的随机字符串
models.UserToken.objects.update_or_create(
user=user_obj, # 查找筛选条件
defaults={ # 添加或者更新的数据
"token": random_str,
}
)
res['token'] = random_str
res['msg'] = '登陆成功'
else:
res['code'] = 0
res['msg'] = '用户名或者密码错误'
return Response(res)
except Exception as e:
res['code'] = 2
res['msg'] = str(e) return Response(res)

通过上面的代码我们将token返回给了用户,那么以后用户不管发送什么请求,都要带着我给它的token值来访问,认证token通过才行,并且更新token。

将来有些数据接口是必须要求用户登陆之后才能获取到数据,所以将来用户登陆完成之后,每次再过来请求,都要带着token来,作为身份认证的依据。

DRF内置的认证组件

在DRF的全局配置信息中,有DRF内置组件的相关配置 :

# 基于django基础配置信息上的drf框架的配置信息

REST_FRAMEWORK = {

    ...

    'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
), ... }

补充:

django项目的request对象中有一个user属性,是一个默认的假用户 AnonymousUser ,当用户未登录admin后台管理系统时,request.user = AnonymousUser

若登录了admin后台,在django内置的认证系统中,request.user = 当前登录用户

DRF中内置的认证系统 'rest_framework.authentication.SessionAuthentication'

跟django中的认证系统挂钩的,使用的也是admin后台的用户信息

DRF内置组件依据session信息做认证,根据上面的叙述,session不适合做大型项目的认证载体,太重了!所以我们可以借助DRF内置的认证系统进行自定义认证系统。

以下是其认证机制的部分源码实现:

def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise if user_auth_tuple is not None:
self._authenticator = authenticator
#值得注意的是,self是APIView封装的新的request对象
self.user, self.auth = user_auth_tuple
return #退出了这个函数,函数就不会执行了,不会再循环了,所以如果你的第一个认证类有返回值,那么第二个认证类就不会执行了,所以别忘了return是结束函数的意思,所以如果你有多个认证类,那么返回值放到最后一个类里面
from rest_framework.authentication import BaseAuthentication

# 'BaseAuthentication'这个类源码实现中有个'authenticate'方法,我们可以重写这个类进行自定制咱们的认证系统。
"""
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.")
"""

一、基于drf提供的认证类BaseAuthentication进行自定制认证系统

1、自定义认证类MyAuthentication,继承自BaseAuthentication类且重写其authenticate方法

# utils.auth.py

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed class MyAuthentication(BaseAuthentication): def authenticate(self, request): if 1:
return "aliang", "fengting007" else:
return AuthenticationFailed("认证失败!")

2、全局配置

对自定义的认证类MyAuthentication中的认证流程进行全局配置,即在访问每个url时都要经过自定义的认证逻辑

  • 在settings.py配置文件中进行配置
# 基于django基础配置信息上的drf框架的配置信息

REST_FRAMEWORK = {

    ...

    'DEFAULT_AUTHENTICATION_CLASSES': (

        # 自定义认证类的路径
'four.utils.auth.MyAuthentication', # 注释掉drf内置的session认证系统,使用自己定制的!
# 'rest_framework.authentication.SessionAuthentication',
), ... }

3、局部配置

即在访问某个指定的url时,需要认证后才可以获取到响应页面,而不是访问所有url都需要认证,这就要在指定的url所映射的类视图中进行定制

from rest_framework.views import APIView
from rest_framework.response import Response
from four.utils.auth import MyAuthentication class AuthAPIView(APIView): # 访问AuthAPIView类视图所对应的url请求响应页面时,要经过自定制的MyAuthentication类的认证逻辑!
authentication_classes = [MyAuthentication,] def get(self, request): print(request.user) # 'aliang'
print(request.auth) # 'fengting007' return Response({'msg':'嗨,man!'})

二、不继承drf提供的认证类BaseAuthentication自定制认证类

class MyAuthentication():

    def authenticate_header(self,request):
pass # authenticate方法是固定的,并且必须有个参数,这个参数是新的request对象
def authenticate(self, request): if 1: # 源码中会发现,这个方法会有两个返回值,并且这两个返回值封装到了新的request对象中了,request.user-->用户名 和 request.auth-->token值,这两个值作为认证结束后的返回结果 # 如下操作即:
# request.user = 'aliang'
# request.auth = 'fengting007' return "aliang", "fengting007"

至于此自定义认证类的全局配置以及局部配置的方法与上面的流程是一致的。

# 局部配置示例:
from app01.serializer import BookSerializers
from four.utils.auth import MyAuthentication class BookView(APIView): #认证组件肯定是在get、post等方法执行之前执行的,源码中这个组件是在dispatch的地方调用的
authentication_classes = [MyAuthentication,] #认证类可以写多个,一个一个的顺序验证 def get(self,request): #这样就拿到了上面MyAuthentication类的authenticate方法的两个返回值
print(request.user)
print(request.auth) book_obj_list = models.Book.objects.all()
s_books = BookSerializers(book_obj_list,many=True)
return Response(s_books.data)

DRF内置认证组件之自定义认证系统的更多相关文章

  1. DRF内置权限组件之自定义权限管理类

    DRF内置权限组件permissions 权限控制可以限制用户对于视图的访问和对于具体数据对象的访问. 在执行视图的dispatch()方法前,会先进行视图访问权限的判断 在通过get_object( ...

  2. DRF内置过滤组件与排序组件结合使用

    DRF内置过滤组件Filtering DRF提供了内置过滤组件Filtering,可以结合url路径的改变获取想要的数据,当然用户不可能在url访问路径中自己设置过滤条件,肯定是后端开发人员将前端页面 ...

  3. .Net Core 认证组件之Cookie认证组件解析源码

    接着上文.Net Core 认证系统源码解析,Cookie认证算是常用的认证模式,但是目前主流都是前后端分离,有点鸡肋但是,不考虑移动端的站点或者纯管理后台网站可以使用这种认证方式.注意:基于浏览器且 ...

  4. DRF JWT的用法 & Django的自定义认证类 & DRF 缓存

    JWT 相关信息可参考: https://www.jianshu.com/p/576dbf44b2ae DRF JWT 的使用方法: 1. 安装 DRF JWT # pip install djang ...

  5. Win7下的内置FTP组件的设置详解

    在局域网中共享文件,FTP是比较方便的方案之一.Win7内部集成了FTP,只是设置起来颇费一番功夫.着文以记之. 一.安装FTP组件 由于Win7默认没有安装FTP组件.故FTP的设置第一步就是安装F ...

  6. struts2内置拦截器和自定义拦截器详解(附源码)

    一.Struts2内置拦截器 Struts2中内置类许多的拦截器,它们提供了许多Struts2的核心功能和可选的高级特 性.这些内置的拦截器在struts-default.xml中配置.只有配置了拦截 ...

  7. spring hystrix和内置tomcat组件的参数调优解析

    1. springboot内置tomcat容器的参数配置 server: port: 12021 # server端的socket超时间(毫秒),使用值-1表示没有(即无限)超时,默认值为60000( ...

  8. 源码剖析Django REST framework的认证方式及自定义认证

    源码剖析Django REST framework的认证方式 在前面说过,请求到达REST framework的时候,会对request进行二次封装,在封装的过程中会对客户端发送过来的request封 ...

  9. vue keep-alive内置缓存组件

    1.当组件在keep-alive被切换时将会执行activeted和deactiveted两个生命周期 2.inlude 正则表达式或字符串 ,只有符合条件的组件会被缓存 exclude正则表达式或字 ...

随机推荐

  1. ATX 学习 (四)-atxserver2

    ATXSERVER2 一.main()文件启动 1.首先通过parse_args返回一个Namespace作一些配置,登录页html在SimpleLoginHandler这个里边写着,2.接着通过db ...

  2. 在ShareX里添加流浪图床

    这里以咱流浪图床为例哈:-D 上传目标类型:图像.文件 请求方法:POST 请求URL:https://p.sda1.dev/api/v1/upload_external_noform URL参数:名 ...

  3. 拿下Netty这座城,从现在开始!

    你好,我是彤哥,技术公号主"彤哥读源码"的运营者. 其实,我刚学习Netty的时候,也是很迷茫的,直到有一天,一个同事收到了阿里的offer,他要去阿里做中台了,临走前他偷偷地告诉 ...

  4. 数据湖应用解析:Spark on Elasticsearch一致性问题

    摘要:脏数据对数据计算的正确性带来了很严重的影响.因此,我们需要探索一种方法,能够实现Spark写入Elasticsearch数据的可靠性与正确性. 概述 Spark与Elasticsearch(es ...

  5. 关于C#反射(转载)

    反射的用途:     (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例.     (2)使用Module了解包含模块的程序集以及模块中 ...

  6. 最简单的VScode Python 开发环境配置以及中文化

    前置条件 Python 3.X(2020年了,建议使用Python3.X版本) 一.下载VSCode VSCode官方下载链接 由于安装过程是中文界面,此处略过. 二.VSCode中文化 不需要配置什 ...

  7. Webpack 原理浅析

    作者: 凹凸曼 - 风魔小次郎 背景 Webpack 迭代到4.x版本后,其源码已经十分庞大,对各种开发场景进行了高度抽象,阅读成本也愈发昂贵.但是为了了解其内部的工作原理,让我们尝试从一个最简单的 ...

  8. 接口工具Apifox

    最近发现一款接口测试工具--apifox,我我们很难将它描述为一款接口管理工具 或 接口自测试工具. 官方给了一个简单的公式,更能说明apifox可以做什么. Apifox = Postman + S ...

  9. 使用 MySQLi 和 PDO 向 MySQL 插入数据

    PHP MySQL 插入数据 使用 MySQLi 和 PDO 向 MySQL 插入数据 在创建完数据库和表后,我们可以向表中添加数据. 以下为一些语法规则: PHP 中 SQL 查询语句必须使用引号 ...

  10. Promise核心基础

    基础 Promise 抽象表达:是js中进行异步编程的新的解决方案 具体解释:1.从语法上来说是一个构造函数 2.从功能上来说promise对象用来封装一个异步操作并可以获取其结果 状态改变:0.ne ...