Flask 中 JWT 认证的落地解决方案
在 Flask 中实现 JWT(JSON Web Token)认证有多种常用方案,下面介绍几种典型实现方式和最佳实践。
方案一:手动实现 JWT 认证
手动处理 Token 的生成、验证和过期逻辑,适合需要高度自定义的场景。
from flask import Flask, request, jsonify
import jwt
from datetime import datetime, timedelta
from functools import wraps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key' # 生产环境应从配置文件或环境变量获取
# 生成 JWT
def generate_token(user_id):
payload = {
'user_id': user_id,
'exp': datetime.utcnow() + timedelta(hours=1), # Token 有效期
'iat': datetime.utcnow()
}
return jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')
# 验证 JWT
def decode_token(token):
try:
payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
return payload
except jwt.ExpiredSignatureError:
return None
except jwt.InvalidTokenError:
return None
# Token 认证装饰器
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = None
auth_header = request.headers.get('Authorization')
if auth_header and auth_header.startswith('Bearer '):
token = auth_header.split(' ')[1]
if not token:
return jsonify({'message': 'Token missing!'}), 401
payload = decode_token(token)
if not payload:
return jsonify({'message': 'Invalid token!'}), 401
return f(payload['user_id'], *args, **kwargs)
return decorated
# 登录接口
@app.route('/login', methods=['POST'])
def login():
# 验证用户身份(示例)
data = request.get_json()
username = data.get('username')
password = data.get('password')
# 实际项目中应从数据库验证用户
if username == 'admin' and password == 'password':
token = generate_token(1)
return jsonify({'token': token})
return jsonify({'message': 'Invalid credentials'}), 401
# 需要认证的接口
@app.route('/protected')
@token_required
def protected(user_id):
return jsonify({'message': f'Protected route accessed by user {user_id}'})
if __name__ == '__main__':
app.run(debug=True)
方案二:使用 Flask-JWT-Extended
Flask 的官方扩展,提供更高级的功能(如 Refresh Token、CSRF 保护、自定义错误处理等)。
from flask import Flask, request, jsonify
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token,
create_refresh_token, get_jwt_identity
)
app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'your-secret-key' # 生产环境应从配置文件或环境变量获取
jwt = JWTManager(app)
# 登录接口(生成 Access Token 和 Refresh Token)
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
username = data.get('username')
password = data.get('password')
# 实际项目中应从数据库验证用户
if username == 'admin' and password == 'password':
access_token = create_access_token(identity=username)
refresh_token = create_refresh_token(identity=username)
return jsonify({
'access_token': access_token,
'refresh_token': refresh_token
})
return jsonify({'message': 'Invalid credentials'}), 401
# 使用 Refresh Token 获取新的 Access Token
@app.route('/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
current_user = get_jwt_identity()
new_access_token = create_access_token(identity=current_user)
return jsonify({'access_token': new_access_token})
# 需要认证的接口
@app.route('/protected')
@jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify({'message': f'Protected route accessed by {current_user}'})
if __name__ == '__main__':
app.run(debug=True)
方案三:结合 Flask-RESTful
适合构建 REST API,将 JWT 认证与资源类结合。
from flask import Flask, request, jsonify
from flask_restful import Api, Resource
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token, get_jwt_identity
)
app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'your-secret-key'
api = Api(app)
jwt = JWTManager(app)
# 登录资源
class Login(Resource):
def post(self):
data = request.get_json()
username = data.get('username')
password = data.get('password')
if username == 'admin' and password == 'password':
token = create_access_token(identity=username)
return jsonify({'token': token})
return jsonify({'message': 'Invalid credentials'}), 401
# 受保护的资源
class ProtectedResource(Resource):
@jwt_required()
def get(self):
current_user = get_jwt_identity()
return jsonify({'message': f'Hello, {current_user}! This is protected.'})
# 注册资源
api.add_resource(Login, '/login')
api.add_resource(ProtectedResource, '/protected')
if __name__ == '__main__':
app.run(debug=True)
最佳实践
-
安全存储密钥:
- 密钥不应硬编码在代码中,建议通过环境变量或配置文件管理。
-
Token 有效期:
- Access Token 设置较短有效期(如 15 分钟)。
- Refresh Token 设置较长有效期(如 7 天),用于无感刷新。
-
HTTPS:
- 生产环境必须使用 HTTPS,防止 Token 被拦截。
-
Token 存储:
- 浏览器端推荐使用 HTTP-only Cookie 存储 Token,防止 XSS 攻击。
- 移动端可存储在安全的设备存储中。
-
异常处理:
- 统一处理 Token 过期、无效等异常情况。
-
权限分级:
- 在 Token 中添加角色或权限信息,实现细粒度的访问控制。
推荐扩展
- Flask-JWT-Extended:功能全面,支持 Refresh Token、CSRF 保护等。
- PyJWT:轻量级 JWT 库,适合手动实现自定义逻辑。
根据项目复杂度和需求选择合适的方案,小型项目可考虑手动实现,中大型项目推荐使用 Flask-JWT-Extended。