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文件和目录操作函数小结
Jul 11 Python
python Elasticsearch索引建立和数据的上传详解
Aug 04 Python
python提取xml里面的链接源码详解
Oct 15 Python
在django中使用apscheduler 执行计划任务的实现方法
Feb 11 Python
基于pytorch中的Sequential用法说明
Jun 24 Python
使用OpenCV实现道路车辆计数的使用方法
Jul 15 Python
Python 合并拼接字符串的方法
Jul 28 Python
如何在Anaconda中打开python自带idle
Sep 21 Python
教你怎么用python selenium实现自动化测试
May 27 Python
python+opencv实现视频抽帧示例代码
Jun 11 Python
Python+OpenCV实现在图像上绘制矩形
Mar 21 Python
python图像处理 PIL Image操作实例
Apr 09 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代码
2007/03/03 PHP
详解PHP中的null合并运算符
2015/12/30 PHP
PHP创建word文档的方法(平台无关)
2016/03/29 PHP
ThinkPHP实现转换数据库查询结果数据到对应类型的方法
2017/11/16 PHP
jquery 关键字“拖曳搜索”之“拖曳”以及 图片“提示自适应放大”效果 的实现
2010/04/18 Javascript
js动态创建上传表单通过iframe模拟Ajax实现无刷新
2014/02/20 Javascript
javascript常用函数归纳整理
2014/10/31 Javascript
基于jQuery实现文本框缩放以及上下移动功能
2014/11/24 Javascript
深入探讨javascript中的数据类型
2015/03/04 Javascript
JavaScript实现拖拽网页内元素的方法
2015/04/15 Javascript
Bootstrap Table的使用总结
2016/10/08 Javascript
基于Phantomjs生成PDF的实现方法
2016/11/07 Javascript
JavaScript易错知识点整理
2016/12/05 Javascript
npm 语义版本控制详解
2019/09/10 Javascript
Python开发常用的一些开源Package分享
2015/02/14 Python
Python使用minidom读写xml的方法
2015/06/03 Python
pytorch 把MNIST数据集转换成图片和txt的方法
2018/05/20 Python
Python中logging实例讲解
2019/01/17 Python
python绘制地震散点图
2019/06/18 Python
使用Python进行防病毒免杀解析
2019/12/13 Python
在jupyter notebook 添加 conda 环境的操作详解
2020/04/10 Python
新建文件时Pycharm中自动设置头部模板信息的方法
2020/04/17 Python
Python常用数据分析模块原理解析
2020/07/20 Python
python如何变换环境
2020/07/21 Python
浅析python函数式编程
2020/09/26 Python
总结30个CSS3选择器
2017/04/13 HTML / CSS
Hotels.com泰国:酒店预订网站
2019/11/20 全球购物
《十六年前的回忆》教学反思
2014/02/14 职场文书
2014年医院工作总结
2014/11/20 职场文书
幼儿园大班开学寄语(2015秋季)
2015/05/27 职场文书
薪资证明范本
2015/06/19 职场文书
高三英语教学反思
2016/03/03 职场文书
如何获取numpy array前N个最大值
2021/05/14 Python
JavaScript canvas实现流星特效
2021/05/20 Javascript
mysql中int(3)和int(10)的数值范围是否相同
2021/10/16 MySQL
vue实现列表垂直无缝滚动
2022/04/08 Vue.js