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使用PyV8执行javascript代码示例分享
Dec 04 Python
python中MySQLdb模块用法实例
Nov 10 Python
python检测远程端口是否打开的方法
Mar 14 Python
Python正则获取、过滤或者替换HTML标签的方法
Jan 28 Python
Python3中的真除和Floor除法用法分析
Mar 16 Python
Python中对象的引用与复制代码示例
Dec 04 Python
python 实现将字典dict、列表list中的中文正常显示方法
Jul 06 Python
大家都说好用的Python命令行库click的使用
Nov 07 Python
django连接mysql数据库及建表操作实例详解
Dec 10 Python
Python pip安装模块提示错误解决方案
May 22 Python
全网最详细的PyCharm+Anaconda的安装过程图解
Jan 25 Python
python 爬取腾讯视频评论的实现步骤
Feb 18 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
处理单名多值表单的详解
2013/06/08 PHP
php过滤敏感词的示例
2014/03/31 PHP
php清空(删除)指定目录下的文件,不删除目录文件夹的实现代码
2014/09/04 PHP
PHP无限极分类函数的实现方法详解
2017/04/15 PHP
javascript之对系统的toFixed()方法的修正
2007/05/08 Javascript
关于Aptana Studio生成自动备份文件的解决办法
2009/12/23 Javascript
NodeJS框架Express的模板视图机制分析
2011/07/19 NodeJs
jQuery源码分析-01总体架构分析
2011/11/14 Javascript
jquery实现控制表格行高亮实例
2013/06/05 Javascript
js捕获鼠标滚轮事件代码
2013/12/16 Javascript
Webpack 实现 AngularJS 的延迟加载
2016/03/02 Javascript
js设置和获取自定义属性的方法
2016/10/20 Javascript
微信小程序 获取二维码实例详解
2017/06/23 Javascript
基于vue.js无缝滚动效果
2018/01/25 Javascript
详解vue2.0+vue-video-player实现hls播放全过程
2018/03/02 Javascript
js实现京东秒杀倒计时功能
2019/01/21 Javascript
layui扩展上传组件模拟进度条的方法
2019/09/23 Javascript
Vue 中 filter 与 computed 的区别与用法解析
2019/11/21 Javascript
JS实现简单的表格增删
2020/01/16 Javascript
关于vue3默认把所有onSomething当作v-on事件绑定的思考
2020/05/15 Javascript
vue-cli —— 如何局部修改Element样式
2020/10/22 Javascript
用Python的Tornado框架结合memcached页面改善博客性能
2015/04/24 Python
Django在pycharm下修改默认启动端口的方法
2019/07/26 Python
关于PyTorch 自动求导机制详解
2019/08/18 Python
python绘制彩虹图
2019/12/16 Python
python中用ctypes模拟点击的实例讲解
2020/11/26 Python
Django用内置方法实现简单搜索功能的方法
2020/12/18 Python
高山背包:High Sierra
2017/11/23 全球购物
Smallable意大利家庭概念店:设计师童装及家居装饰
2018/01/08 全球购物
农业资源与环境专业自荐信范文
2013/12/30 职场文书
班级聚会策划书
2014/01/16 职场文书
弄虚作假心得体会
2014/09/10 职场文书
个人收入证明模板
2014/09/18 职场文书
单位实习鉴定评语
2015/01/04 职场文书
技术支持岗位职责
2015/02/13 职场文书
Vue操作Storage本地化存储
2022/04/29 Vue.js