前后端分离项目必备: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)

最佳实践

  1. 安全存储密钥

    • 密钥不应硬编码在代码中,建议通过环境变量或配置文件管理。
  2. Token 有效期

    • Access Token 设置较短有效期(如 15 分钟)。
    • Refresh Token 设置较长有效期(如 7 天),用于无感刷新。
  3. HTTPS

    • 生产环境必须使用 HTTPS,防止 Token 被拦截。
  4. Token 存储

    • 浏览器端推荐使用 HTTP-only Cookie 存储 Token,防止 XSS 攻击。
    • 移动端可存储在安全的设备存储中。
  5. 异常处理

    • 统一处理 Token 过期、无效等异常情况。
  6. 权限分级

    • 在 Token 中添加角色或权限信息,实现细粒度的访问控制。

推荐扩展

  • Flask-JWT-Extended:功能全面,支持 Refresh Token、CSRF 保护等。
  • PyJWT:轻量级 JWT 库,适合手动实现自定义逻辑。

根据项目复杂度和需求选择合适的方案,小型项目可考虑手动实现,中大型项目推荐使用 Flask-JWT-Extended。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值