python-jwt用户认证食用教学的实现方法


Posted in Python onJanuary 19, 2021

jwt

jwt的作用

json web token,一般用于用户认证就是做用户登录的(前后端分离/微信小程序/app开发)

python-jwt用户认证食用教学的实现方法

基于传统的token认证

用户登录,服务端返回token,并将token保存在服务端,
以后用户再来访问时,需要携带token,服务端获取token后,再去数据库中获取token进行校验

jwt

用户登录,服务端给用户返回一个token(服务端不保存)
以后用户再来访问,需要携带token,服务端获取token后,再做token的校验----进行算法校验

优势:相较于传统的token相比,它无需在服务端保存token

jwt的实现原理

第一步,用户提交用户名和密码给服务器,如果登录成功,使用jwt创建一个token,并给用户返回.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

注意:jwt生成的token是由三段字符串组成,并且用.连接起来的

第一段字符串,HEADER,内部包含了算法/token类型,

json转换成字符串,然后做一个base64url加密(base64加密;+_),加密再加替换

{
 "alg": "HS256",
 "typ": "JWT"
}

第二段字符串,PAYLOAD,自定义的值

让json转换成字符串,然后做一个base64url加密(base64加密;+_),加密再加替换

{
 "sub": "1234567890",
 "name": "John Doe",
 "iat": 1516239022 # 前两个随便写,最后一个是超时时间
}

第三段字符串:他会将第一段加密之后的值,和第二段加密之后的值通过.拼接起来

第一步:第1,2部分的密文拼接起来

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

第二步:对前两部分密文进行HS256加密 + 加盐
第三步:对HS256加密后的密文再做base64url加密

以后用户再来访问的时候,需要携带token,后端需要对token进行校验

获取token

第一步: 对token进行切割,通过点切割成三部分

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

第二步: 对第二段进行 base64url 解密,并获取payload信息,检测token是否超时了?

{
 "sub": "1234567890",
 "name": "John Doe",
 "iat": 1516239022 # 前两个随便写,最后一个是超时时间
}

第三步 :把第1,2段拼接,再次执行HS256加密

第一步:第1,2部分的密文拼接起来

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

第二步:对前两部分密文进行HS256加密 + 加盐

密文 = base64解密(SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c)
如果密文相等,表示token未被修改过(认证通过)

jwt的引用

pip install pyjwt
pyjwt.encode 生成token

pyjwt.decode token解密

原理性的东西

python-jwt用户认证食用教学的实现方法

python-jwt用户认证食用教学的实现方法

基于jwt和drf实现用户认证

1.路由

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.conf.urls import url, include
from api import views

urlpatterns = [ url('^login/$', views.LoginView.as_view()), url('^order/$', views.OrderView.as_view()),]

views

from rest_framework.views import APIView
from rest_framework.response import Response

from utils.jwt_auth import create_token
from extensions.auth import JwtQueryParamAuthentication, JwtAuthorizationAuthentication


class LoginView(APIView):
 def post(self, request, *args, **kwargs):
 """ 用户登录 """
 user = request.POST.get('username')
 pwd = request.POST.get('password')

 # 检测用户和密码是否正确,此处可以在数据进行校验。
 if user == 'wupeiqi' and pwd == '123':
  # 用户名和密码正确,给用户生成token并返回
  token = create_token({'username': 'wupeiqi'})
  return Response({'status': True, 'token': token})
 return Response({'status': False, 'error': '用户名或密码错误'})


class OrderView(APIView):
 # 通过url传递token
 authentication_classes = [JwtQueryParamAuthentication, ]

 # 通过Authorization请求头传递token
 # authentication_classes = [JwtAuthorizationAuthentication, ]

 def get(self, request, *args, **kwargs):
 print(request.user, request.auth)
 return Response({'data': '订单列表'})

 def post(self, request, *args, **kwargs):
 print(request.user, request.auth)
 return Response({'data': '添加订单'})

 def put(self, request, *args, **kwargs):
 print(request.user, request.auth)
 return Response({'data': '修改订单'})

 def delete(self, request, *args, **kwargs):
 print(request.user, request.auth)
 return Response({'data': '删除订单'})

settings

SECRET_KEY = '-(e4!74gqo8q@v-y#0cz9e7aeux4qx-pl1xw#05co4avr8r+r0'

REST_FRAMEWORK = {
 "DEFAULT_VERSIONING_CLASS": 'rest_framework.versioning.URLPathVersioning',
 "ALLOWED_VERSIONS": ['v1', "v2"] #两个认证版本
}

extensions.auth

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from utils.jwt_auth import parse_payload


class JwtQueryParamAuthentication(BaseAuthentication):
 """
 用户需要在url中通过参数进行传输token,例如:
 http://www.pythonav.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
 """

 def authenticate(self, request):
 token = request.query_params.get('token')
 payload = parse_payload(token)
 if not payload['status']:
  raise exceptions.AuthenticationFailed(payload)

 # 如果想要request.user等于用户对象,此处可以根据payload去数据库中获取用户对象。
 return (payload, token)


class JwtAuthorizationAuthentication(BaseAuthentication):
 """
 用户需要通过请求头的方式来进行传输token,例如:
 Authorization:jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
 """

 def authenticate(self, request):

 # 非登录页面需要校验token
 authorization = request.META.get('HTTP_AUTHORIZATION', '')
 auth = authorization.split()
 if not auth:
  raise exceptions.AuthenticationFailed({'error': '未获取到Authorization请求头', 'status': False})
 if auth[0].lower() != 'jwt':
  raise exceptions.AuthenticationFailed({'error': 'Authorization请求头中认证方式错误', 'status': False})

 if len(auth) == 1:
  raise exceptions.AuthenticationFailed({'error': "非法Authorization请求头", 'status': False})
 elif len(auth) > 2:
  raise exceptions.AuthenticationFailed({'error': "非法Authorization请求头", 'status': False})

 token = auth[1]
 result = parse_payload(token)
 if not result['status']:
  raise exceptions.AuthenticationFailed(result)

 # 如果想要request.user等于用户对象,此处可以根据payload去数据库中获取用户对象。
 return (result, token)

utils.jwt_auth

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import jwt
import datetime
from jwt import exceptions

JWT_SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='

def create_token(payload, timeout=20):
 """
 :param payload: 例如:{'user_id':1,'username':'wupeiqi'}用户信息
 :param timeout: token的过期时间,默认20分钟
 :return:
 """
 headers = {
 'typ': 'jwt',
 'alg': 'HS256'
 }
 payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
 result = jwt.encode(payload=payload, key=JWT_SALT, algorithm="HS256", headers=headers).decode('utf-8')
 return result

def parse_payload(token):
 """
 对token进行和发行校验并获取payload
 :param token:
 :return:
 """
 result = {'status': False, 'data': None, 'error': None}
 try:
 verified_payload = jwt.decode(token, JWT_SALT, True)
 result['status'] = True
 result['data'] = verified_payload
 except exceptions.ExpiredSignatureError:
 result['error'] = 'token已失效'
 except jwt.DecodeError:
 result['error'] = 'token认证失败'
 except jwt.InvalidTokenError:
 result['error'] = '非法的token'
 return result

扩展

pip3 install djangorestframework-jwt 和上面的类似不建议使用,就是加了一些配置文件,只能在drf中用,太局限l

djangorestframework-jwt 本质是调用pyjwt实现的

使用场景两端开发,app,小程序开发!

到此这篇关于python-jwt用户认证食用教学的文章就介绍到这了,更多相关python-jwt认证内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python访问MySQL封装的常用类实例
Nov 11 Python
在python中利用numpy求解多项式以及多项式拟合的方法
Jul 03 Python
Python 获取 datax 执行结果保存到数据库的方法
Jul 11 Python
Django使用Jinja2模板引擎的示例代码
Aug 09 Python
python中的函数递归和迭代原理解析
Nov 14 Python
wxPython实现画图板
Aug 27 Python
PyQT5速成教程之Qt Designer介绍与入门
Nov 02 Python
python 通过 pybind11 使用Eigen加速代码的步骤
Dec 07 Python
python之openpyxl模块的安装和基本用法(excel管理)
Feb 03 Python
python 远程执行命令的详细代码
Feb 15 Python
Python集合set()使用的方法详解
Mar 18 Python
5个pandas调用函数的方法让数据处理更加灵活自如
Apr 24 Python
使用Python爬虫爬取小红书完完整整的全过程
Jan 19 #Python
python 自动识别并连接串口的实现
Jan 19 #Python
python爬取抖音视频的实例分析
Jan 19 #Python
python中的插入排序的简单用法
Jan 19 #Python
Python实现淘宝秒杀功能的示例代码
Jan 19 #Python
Python爬虫后获取重定向url的两种方法
Jan 19 #Python
详解Python+Selenium+ChromeDriver的配置和问题解决
Jan 19 #Python
You might like
功能齐全的PHP发送邮件类代码附详细说明
2008/07/10 PHP
php chr() ord()中文截取乱码问题解决方法
2008/09/08 PHP
使ecshop模板中可引用常量的实现方法
2011/06/02 PHP
codeigniter自带数据库类使用方法说明
2014/03/25 PHP
用PHP和Shell写Hadoop的MapReduce程序
2014/04/15 PHP
CodeIgniter CLI模式简介
2014/06/17 PHP
laravel框架中控制器的创建和使用方法分析
2019/11/23 PHP
js如何获取兄弟、父类等节点
2014/01/06 Javascript
jquery遍历checkbox介绍
2014/02/21 Javascript
jquery中的ajax方法怎样通过JSONP进行远程调用
2014/05/04 Javascript
Node.js中使用Buffer编码、解码二进制数据详解
2014/08/16 Javascript
jquery引用方法时传递参数原理分析
2014/10/13 Javascript
关于Javascript加载执行优化的研究报告
2014/12/16 Javascript
jQuery控制元素显示、隐藏、切换、滑动的方法总结
2015/04/16 Javascript
深入理解JavaScript中Ajax
2016/08/02 Javascript
JS查找字符串中出现次数最多的字符
2016/09/05 Javascript
D3.js进阶系列之CSV表格文件的读取详解
2017/06/06 Javascript
Vue中封装input组件的实例详解
2017/10/17 Javascript
解决vue组件中使用v-for出现告警问题及v for指令介绍
2017/11/11 Javascript
解决Layui中layer报错的问题
2019/09/03 Javascript
echarts实现折线图的拖拽效果
2019/12/19 Javascript
Scrapy框架爬取Boss直聘网Python职位信息的源码
2019/02/22 Python
深入了解NumPy 高级索引
2020/07/24 Python
python 装饰器的实际作用有哪些
2020/09/07 Python
纯CSS3制作的简洁蓝白风格的登录模板(非IE效果更好)
2013/08/11 HTML / CSS
Expedia泰国:预订机票、酒店和旅游包(航班+酒店)
2016/09/27 全球购物
阿联酋电子产品购物网站:Menakart
2017/09/15 全球购物
可以使用抽象函数重写基类中的虚函数吗
2013/06/02 面试题
技术总监个人的自我评价范文
2013/12/18 职场文书
后进生转化工作制度
2014/01/17 职场文书
党课培训主持词
2014/04/01 职场文书
《海伦?凯勒》教学反思
2014/04/17 职场文书
文明班级建设方案
2014/05/15 职场文书
公务员培的训心得体会
2014/09/01 职场文书
小学五年级语文上册教学计划
2015/01/22 职场文书
python垃圾回收机制原理分析
2022/04/13 Python