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库urllib与urllib2主要区别分析
Jul 13 Python
Python中使用装饰器和元编程实现结构体类实例
Jan 28 Python
Python装饰器使用示例及实际应用例子
Mar 06 Python
Python ValueError: invalid literal for int() with base 10 实用解决方法
Jun 21 Python
解决python Markdown模块乱码的问题
Feb 14 Python
使用PyCharm进行远程开发和调试的实现
Nov 04 Python
Python创建数字列表的示例
Nov 28 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
Dec 04 Python
Python 实现加密过的PDF文件转WORD格式
Feb 04 Python
Django admin 实现search_fields精确查询实例
Mar 30 Python
keras 自定义loss损失函数,sample在loss上的加权和metric详解
May 23 Python
Python 视频画质增强
Apr 28 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垃圾代码优化操作代码
2010/08/05 PHP
php设计模式之观察者模式的应用详解
2013/05/21 PHP
php去掉文件前几行的方法
2015/07/29 PHP
PHP读取并输出XML文件数据的简单实现方法
2017/12/22 PHP
PHP 应用容器化以及部署方法
2018/02/12 PHP
jQuery UI Datepicker length为空或不是对象错误的解决方法
2010/12/19 Javascript
使用GruntJS构建Web程序之安装篇
2014/06/04 Javascript
JavaScript中iframe实现局部刷新的几种方法汇总
2016/01/06 Javascript
Nodejs进阶:核心模块net入门学习与实例讲解
2016/11/21 NodeJs
浅谈javascript的url参数parse和build函数
2017/03/04 Javascript
angular2路由切换改变页面title的示例代码
2017/08/23 Javascript
微信小程序实现页面跳转传值的方法
2017/10/12 Javascript
详解Vue文档中几个易忽视部分的剖析
2018/03/24 Javascript
layui 表单标签的校验方法
2019/09/04 Javascript
使用jQuery实现掷骰子游戏
2019/10/24 jQuery
uniapp与webview之间的相互传值的实现
2020/06/29 Javascript
vue在图片上传的时候压缩图片
2020/11/18 Vue.js
学习python (1)
2006/10/31 Python
python单链表实现代码实例
2013/11/21 Python
python使用datetime模块计算各种时间间隔的方法
2015/03/24 Python
python查找目录下指定扩展名的文件实例
2015/04/01 Python
Python实现的批量修改文件后缀名操作示例
2018/12/07 Python
python3+selenium实现qq邮箱登陆并发送邮件功能
2019/01/23 Python
python版DDOS攻击脚本
2019/06/12 Python
python随机模块random使用方法详解
2020/02/14 Python
Sunglasses Shop丹麦:欧洲第一的太阳镜在线销售网站
2017/10/22 全球购物
阿根廷在线宠物商店:Puppis
2018/03/23 全球购物
How to spawning asynchronous work in J2EE
2016/08/29 面试题
vue实现倒计时功能
2021/03/24 Vue.js
员工年终演讲稿
2014/01/03 职场文书
生物学学生自我评价
2014/01/17 职场文书
HTML5来实现本地文件读取和写入的实现方法
2021/05/25 HTML / CSS
python实现语音常用度量方法的代码详解
2021/05/25 Python
mysql获取指定时间段中所有日期或月份的语句(不设存储过程,不加表)
2021/06/18 MySQL
mysql优化之query_cache_limit参数说明
2021/07/01 MySQL
移除Selenium中window.navigator.webdriver值
2022/06/10 Python