JWT是一种用于身份验证和授权的安全传输方式,全称为JSON Web Token。
JSON Web Token (JWT)由三个部分组成:Header,Payload和Signature。
- Header部分指定JWT使用的签名算法,例如HMAC SHA256或RSA。
- Payload部分包含与身份验证和授权相关的信息,例如用户ID和访问权限等。
- Signature部分通过使用Header和Payload部分的内容以及密钥来生成签名。用于验证JWT是否被篡改。
JWT的工作流程如下:
- 用户通过用户名和密码进行身份验证,身份验证成功后,服务器生成JWT。
- 服务器将JWT返回给客户端,客户端将JWT存储在本地。
- 客户端在每个请求中使用JWT作为身份验证凭证,服务器从JWT中验证用户的身份和访问权限。
JWT的优点是:
- 跨平台:JWT是基于JSON的标准,因此可以轻松地在不同平台之间传输。
- 安全:JWT的签名可以防止JWT在传输过程中被篡改。
- 无状态:服务器不需要在自己的存储中保存JWT,使得JWT非常适合在无状态的REST API中使用。
关于JWT的详细说明大家可以去看这个视频 https://www.bilibili.com/video/BV1ob4y1Y7Ep/
1、安装Flask-JWT-Extended库
pip install flask-jwt-extended
2、基本使用
flask_jwt_extended
库用的最多的几个方法:
create_access_token()
用来创建 Token 令牌create_refresh_toke()
用来创建刷新 Token的令牌get_jwt_identity()
用来根据令牌取得之前的 identity 信息jwt_required()
这是一个装饰器,用来保护 flask 节点
2.1、导入使用
from flask_jwt_extended import JWTManager
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
2.1、初始化
import datetime
from flask_jwt_extended import JWTManager
from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-secret' # 设置秘钥
# 配置JWT
app.config['JWT_SECRET_KEY'] = 'super-secret' # 设置JWT秘钥
app.config['JWT_TOKEN_LOCATION'] = ['headers', 'cookies'] # 设置token的位置
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = datetime.timedelta(days=7) # 设置access_token过期时间
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = datetime.timedelta(days=1) # 设置refresh_token过期时间
app.config['JWT_COOKIE_SECURE'] = True # 设置cookie只能通过https传输
app.config['JWT_ACCESS_COOKIE_PATH'] = '/' # 设置access_token的cookie路径
app.config['JWT_REFRESH_COOKIE_PATH'] = '/refresh' # 设置refresh_token的cookie路径
# 初始化jwt
jwt = JWTManager(app)
2.2、flask_jwt_extended配置说明
JWT_TOKEN_LOCATION = ['cookies']
# ["headers", "cookies", "json", "query_string"]
# 指定JWT令牌在哪个位置进行身份验证。在这里,令牌存储在cookie中
JWT_COOKIE_SECURE = True
# 指定JWT cookie是否需要安全的HTTPS协议传输
JWT_ACCESS_COOKIE_PATH = '/'
JWT_REFRESH_COOKIE_PATH = '/refresh'
# 分别指定JWT访问令牌和刷新令牌的cookie路径
JWT_CSRF_IN_COOKIES = True
JWT_COOKIE_CSRF_PROTECT = True
# 启用JWT的CSRF保护。前者指定JWT的CSRF令牌是否存储在cookie中,后者指定是否需要验证来自客户端的CSRF令牌
JWT_ACCESS_CSRF_HEADER_NAME = 'X-CSRF-TOKEN-ACCESS'
JWT_REFRESH_CSRF_HEADER_NAME = 'X-CSRF-TOKEN-REFRESH'
# 指定JWT访问令牌和刷新令牌的CSRF请求头名称
JWT_ACCESS_CSRF_COOKIE_NAME = 'csrf_access_token'
JWT_REFRESH_CSRF_COOKIE_NAME = 'csrf_refresh_token'
# 指定JWT访问令牌和刷新令牌的CSRF cookie名称
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(days=7)
JWT_REFRESH_TOKEN_EXPIRES = datetime.timedelta(days=1)
# 分别指定JWT访问令牌和刷新令牌的过期时间。在这里,访问令牌的过期时间是7天,刷新令牌的过期时间是1天
2.3、登陆成功后生成JWT
这里我用的json来获取到请求中的用户名和密码,如果登陆成功后,会把token
返回给前端。
@app.route('/login', methods=['POST'])
def login():
# 从请求的json数据中获取用户名和密码
username = request.json.get('username', None)
password = request.json.get('password', None)
# 验证用户名和密码是否正确
if username != 'admin' or password != '123456':
return jsonify({'code': 401, 'msg': '用户名或密码错误'})
else:
# 生成access_token
access_token = create_access_token(identity=username)
# 将生成的token返回给前端
response = jsonify({'code': 200, 'msg': '登录成功', 'access_token': access_token})
return response
我们使用Apifox来测试一下我们刚刚的示例。成功拿到这里的JWT
了。
2.4、jwt_required装饰器的使用
jwt_required主要是对接口进行鉴权,@jwt_required(locations=['headers', 'cookies'])
是 Flask-JWT-Extended 扩展提供的装饰器,用于保护需要身份验证的端点(endpoint)。它除了检查请求的 Authorization
头是否包含有效的 JSON Web Token(JWT),还会检查请求中 cookies 中是否包含有效的 JWT Token。
@app.route('/test', methods=['POST'])
@jwt_required(locations=['headers', 'cookies'])
def test():
# 获取当前token的身份信息
current_identity = get_jwt_identity()
# 判断当前token是否存在
if current_identity:
# 返回当前token的身份信息
return jsonify({'code': 200, 'msg': '请求成功', 'current_identity': current_identity})
else:
# 返回错误信息
return jsonify({'code': 401, 'msg': '请先登录认证'})
我们使用Apifox分别来测试一下没有在请求中携带token和携带了token的效果。这样能够直观的体现出jwt_required
的作用.
2.4.1、未携带JWT
这句话的意思是说:缺少 JWT(JSON Web Token)在请求头或者 Cookie 中(缺少授权头;缺少名为“access_token_cookie”的 Cookie)。也就是我们要在header
和Cookie
中携带 JWT.
2.4.2、请求头携带JWT
我们要设置请求header
标头来验证请求(Bearer Token),就是我们获取的JWT,例如:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY4MjUzMDE4MiwianRpIjoiOGUyM2U0M2MtZTVjYy00ZjE1LTk1MzYtZDgyNWJiN2EzNTE2IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImFkbWluIiwibmJmIjoxNjgyNTMwMTgyLCJjc3JmIjoiMzY2MDMxZTMtYzMzYS00MzQwLTliMjAtYTFkNDc0ZjI3Y2FhIiwiZXhwIjoxNjgzMTM0OTgyfQ.qIaJuTj471pcmitm_Ff6B6h9NPZXZo6iNAbtFXK8n1A
下面这个示例,我们在请求header
标头添加了上面的参数就可以验证成功了
3、完整代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2023/4/27 0:55
# @Author : Small tred
# @FileName: app.py.py
# @Software: PyCharm
# @Blog : https://www.hecady.com
import datetime
from flask_jwt_extended import JWTManager, set_access_cookies
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
from flask import Flask, request, jsonify
app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-secret' # 设置秘钥
# 配置JWT
app.config['JWT_SECRET_KEY'] = 'super-secret' # 设置JWT秘钥
app.config['JWT_TOKEN_LOCATION'] = ['headers', 'cookies'] # 设置token的位置
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = datetime.timedelta(days=7) # 设置access_token过期时间
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = datetime.timedelta(days=1) # 设置refresh_token过期时间
app.config['JWT_COOKIE_SECURE'] = True # 设置cookie只能通过https传输
app.config['JWT_ACCESS_COOKIE_PATH'] = '/' # 设置access_token的cookie路径
app.config['JWT_REFRESH_COOKIE_PATH'] = '/refresh' # 设置refresh_token的cookie路径
# 初始化jwt
jwt = JWTManager(app)
@app.route('/login', methods=['POST'])
def login():
# 从请求的json数据中获取用户名和密码
username = request.json.get('username', None)
password = request.json.get('password', None)
# 验证用户名和密码是否正确
if username != 'admin' or password != '123456':
return jsonify({'code': 401, 'msg': '用户名或密码错误'})
else:
# 生成access_token
access_token = create_access_token(identity=username)
# 将生成的token返回给前端
response = jsonify({'code': 200, 'msg': '登录成功', 'access_token': access_token})
return response
@app.route('/test', methods=['POST'])
@jwt_required(locations=['headers', 'cookies'])
def test():
# 获取当前token的身份信息
current_identity = get_jwt_identity()
# 判断当前token是否存在
if current_identity:
# 返回当前token的身份信息
return jsonify({'code': 200, 'msg': '请求成功', 'current_identity': current_identity})
else:
# 返回错误信息
return jsonify({'code': 401, 'msg': '请先登录认证'})
if __name__ == '__main__':
app.run(debug=True)
4、最后
至此flask_jwt_extended
基本的使用方法就到这里了,都是我自己的一些,欢迎来讨论。
后面有时间也会持续更新。
下一篇文章讲一下使用携带cookie和设置cookie