大多数使用 JWT 的项目其实都是使用的 JWS(JSON Web Signature), JWT 并不等于 JWS,JWS 只是JWT的一种实现,除了 JWS 外,JWE(JSON Web Encryption) 也是JWT的一种实现。
一般我们使用 JWS 完全满足我们的需求。
安装依赖
```
(.venv) root@airvip:~/python_app/flask-demo# pip install flask-jwt-extended
```
常用配置
* `JWT_REFRESH_TOKEN_EXPIRES` 刷新 token 过期时间,默认 30 天。
* `JWT_ACCESS_TOKEN_EXPIRES` token 过期时间,默认 15 分钟
* `JWT_SECRET_KEY` 基于对称的签名算法所需的密钥,如 : `HS*`。如果没有设置,则使用 flask 的 `SECRET_KEY`值。
修改配置文件 `config.py`
```
class Config(object):
SECRET_KEY = "AIRVip123456airvip"
# 数据库、cache 配置省略
# JWT
JWT_ACCESS_TOKEN_EXPIRES = 7200
```
对 `app` 目录下的 ` __init__` 初始化文件进行如下改造,添加 `jwt` 模块
```
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_caching import Cache
from flask_jwt_extended import JWTManager
import logging
from logging.handlers import RotatingFileHandler
from config import config_map
from app.utils.commons import ReCoverter
db = SQLAlchemy()
cache = Cache()
# 创建 jwt 对象
jwt = JWTManager()
logging.basicConfig(level=logging.ERROR)
file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024, backupCount=10)
formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
file_log_handler.setFormatter(formatter)
logging.getLogger().addHandler(file_log_handler)
def create_app(config_name):
app = Flask(__name__)
config_class = config_map[config_name]
app.config.from_object(config_class)
db.init_app(app)
cache.init_app(app)
# 使用 app 初始化 jwt
jwt.init_app(app)
app.url_map.converters["re"] = ReCoverter
from app import api_1_0
app.register_blueprint(api_1_0.bp, url_prefix="/api/v1.0")
from app import html
app.register_blueprint(html.html)
return app
```
对 `app/api_1_0/controller` 下的 `passport.py` 控制器进行如下改造
```
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
from app.api_1_0 import bp
from app import cache
from flask import request,jsonify
from flask_jwt_extended import (
create_access_token, create_refresh_token, jwt_refresh_token_required,
jwt_required, get_jwt_identity
)
@bp.route('/login', methods=['POST'])
def login():
username = request.get_json()['username']
# 验证自己做
ret = {
"access_token": create_access_token(identity=username),
"refresh_token": create_refresh_token(identity=username)
}
return jsonify(ret)
@bp.route('/refresh', methods=['POST'])
@jwt_refresh_token_required
def refresh():
current_user = get_jwt_identity()
ret = {
'access_token': create_access_token(identity=current_user)
}
return jsonify(ret)
@bp.route('/protected', methods=['GET'])
@jwt_required
def protected():
username = get_jwt_identity()
return jsonify(username=username)
```
**测试**
```
root@airvip:~# curl 127.0.0.1:5000/api/v1.0/login -X POST -H 'Content-Type: application/json' -d '{"username":"airvip"}'
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA0MjA4ODUsIm5iZiI6MTYxMDQyMDg4NSwianRpIjoiZjQwOGY0YWYtMTllMi00NzU1LWE4NWQtNzMxOTdlNzg1YjMxIiwiZXhwIjoxNjEwNDI4MDg1LCJpZGVudGl0eSI6ImFpcnZpcCIsImZyZXNoIjpmYWxzZSwidHlwZSI6ImFjY2VzcyJ9.vmgt9EMqJjP17XQ7Sxcc1fU5FIsNzrKEvCPqZLBwCgM",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA0MjA4ODUsIm5iZiI6MTYxMDQyMDg4NSwianRpIjoiNDk2YjgyMjItYTI3My00MGNhLWJlMmMtMTZkMWQ1MDU5YzY5IiwiZXhwIjoxNjEzMDEyODg1LCJpZGVudGl0eSI6ImFpcnZpcCIsInR5cGUiOiJyZWZyZXNoIn0.JiSlX81RR4QctrYq4jdThEIYGEIWHbgZi94Ra09U7c8"
}
# 刷新 token ,发送 http 请求的 header 用的是登录返回的 refresh_token
root@airvip:~# curl 127.0.0.1:5000/api/v1.0/refresh -X POST -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA0MjA4ODUsIm5iZiI6MTYxMDQyMDg4NSwianRpIjoiNDk2YjgyMjItYTI3My00MGNhLWJlMmMtMTZkMWQ1MDU5YzY5IiwiZXhwIjoxNjEzMDEyODg1LCJpZGVudGl0eSI6ImFpcnZpcCIsInR5cGUiOiJyZWZyZXNoIn0.JiSlX81RR4QctrYq4jdThEIYGEIWHbgZi94Ra09U7c8'
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA0MjA5MTAsIm5iZiI6MTYxMDQyMDkxMCwianRpIjoiN2Q5ZDBhOWYtZjc1OC00NzBmLThlNjUtZDQyMjk2YTgxZTRhIiwiZXhwIjoxNjEwNDI4MTEwLCJpZGVudGl0eSI6ImFpcnZpcCIsImZyZXNoIjpmYWxzZSwidHlwZSI6ImFjY2VzcyJ9.xj71pS97iXEVR68BPy1H8pKs82bITnqhOdLbHjlIr3w"
}
# 之后需要验证的方法,发送 http 请求的 header 用 access_token
root@airvip:~# curl 127.0.0.1:5000/api/v1.0/protected -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA0MjA5MTAsIm5iZiI6MTYxMDQyMDkxMCwianRpIjoiN2Q5ZDBhOWYtZjc1OC00NzBmLThlNjUtZDQyMjk2YTgxZTRhIiwiZXhwIjoxNjEwNDI4MTEwLCJpZGVudGl0eSI6ImFpcnZpcCIsImZyZXNoIjpmYWxzZSwidHlwZSI6ImFjY2VzcyJ9.xj71pS97iXEVR68BPy1H8pKs82bITnqhOdLbHjlIr3w'
{
"username": "airvip"
}
root@airvip:~#
```
![jwt 测试](https://img.kancloud.cn/18/f4/18f40c0d819252a5b648eec2fee86bff_1051x337.png)
传送门:[Flask-JWT-Extended’s 更多使用技巧](https://flask-jwt-extended.readthedocs.io/en/latest/)