基于 Flask 的 JWT 使用详解:原理、应用与实践

230 阅读4分钟

什么是 JWT?

JWT,全称为 JSON Web Token,是一种用于客户端与服务端安全通信的开放标准(RFC 7519)。JWT 的主要用途是 身份验证信息交换。它以紧凑、安全的方式,将信息封装成 JSON 对象,方便传输和验证。


JWT 的组成

一个完整的 JWT 是一个由三部分组成的字符串,每部分用 . 分隔:

css
复制代码
Header.Payload.Signature
  1. Header(头部) : 头部定义了令牌的类型和签名算法,例如:

    json
    复制代码
    {
        "alg": "HS256",
        "typ": "JWT"
    }
    

    经过 Base64 编码后会变成类似:

    复制代码
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    
  2. Payload(载荷) : 载荷是实际存储信息的地方,通常包含用户身份信息(sub)和过期时间(exp)。例如:

    json
    复制代码
    {
        "sub": "1234567890",
        "name": "John Doe",
        "admin": true,
        "exp": 1716239022
    }
    

    编码后为:

    复制代码
    eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
    
  3. Signature(签名) : 签名用于验证令牌的完整性。由以下公式生成:

    scss
    复制代码
    HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
    

    生成的签名类似:

    复制代码
    SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

完整的 JWT 为:

复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT 的优点

  1. 轻量级:基于 JSON 格式,大小较小,易于传输。
  2. 跨平台:无论客户端是 Web、移动端还是其他平台,都可以轻松使用。
  3. 安全性:签名防篡改,私密信息仅在服务端解密。
  4. 无状态:令牌包含了全部用户信息,无需在服务端存储会话数据。

JWT 的常见应用场景

  1. 身份认证

    • 用户登录成功后,服务端生成 JWT 并返回给客户端。
    • 客户端在每次请求时附加 JWT 到 Authorization 头。
    • 服务端验证 JWT 并授予或拒绝访问。
  2. 信息交换

    • 不同系统间安全传递认证信息。
  3. 单点登录(SSO)

    • JWT 的无状态特性非常适合实现单点登录。

JWT 使用示例

安装依赖

使用 Python 的 Flask 框架实现 JWT 功能,先安装必要的库:

bash
复制代码
pip install flask flask-jwt-extended
创建项目文件

创建一个名为 app.py 的文件,输入以下代码:

python
复制代码
from flask import Flask, jsonify, request
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity

app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'your_secret_key'  # 设置密钥

jwt = JWTManager(app)

# 用户登录,返回 JWT
@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username', None)
    password = request.json.get('password', None)
    
    # 简单的用户验证逻辑
    if username != 'admin' or password != 'password':
        return jsonify({"msg": "Bad username or password"}), 401
    
    # 生成 JWT
    access_token = create_access_token(identity=username)
    return jsonify(access_token=access_token)

# 受保护的路由,需要 JWT 验证
@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():
    current_user = get_jwt_identity()
    return jsonify(logged_in_as=current_user), 200

if __name__ == '__main__':
    app.run(debug=True)
代码解析
  1. 配置 JWT 密钥

    • JWT_SECRET_KEY 是用来签名令牌的密钥,必须保密。
  2. 生成令牌

    • 使用 create_access_token 函数创建令牌,identity 参数用来存储用户标识信息。
  3. 验证令牌

    • 在受保护的路由中,使用 @jwt_required() 装饰器验证请求中的 JWT。
    • 如果验证成功,可以通过 get_jwt_identity() 获取当前用户信息。
运行项目

在终端运行以下命令:

bash
复制代码
python app.py

使用工具(如 Postman)测试以下流程:

  1. 登录获取 JWT

    • POST 请求:http://127.0.0.1:5000/login

    • 请求体:

      json
      复制代码
      {
          "username": "admin",
          "password": "password"
      }
      
    • 响应:

      json
      复制代码
      {
          "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
      }
      
  2. 访问受保护资源

    • GET 请求:http://127.0.0.1:5000/protected

    • 请求头:

      makefile
      复制代码
      Authorization: Bearer <your_access_token>
      
    • 响应:

      json
      复制代码
      {
          "logged_in_as": "admin"
      }
      

安全注意事项

  1. 设置过期时间

    • 默认情况下,JWT 是永久有效的。建议设置令牌过期时间,例如:

      python
      复制代码
      from datetime import timedelta
      app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=1)
      
  2. 使用 HTTPS

    • 在生产环境中,务必使用 HTTPS 以防止令牌被中间人攻击窃取。
  3. 防止重复使用令牌

    • 实现令牌的黑名单机制,注销时将令牌加入黑名单。

总结

JWT 是一种轻量级的身份验证方式,因其安全性和跨平台特性而广泛应用于现代 Web 开发。在本篇文章中,我们了解了 JWT 的组成、应用场景,并通过 Flask 展示了如何使用 JWT 实现用户认证。掌握 JWT 的使用,不仅可以提升项目的安全性,还能提高系统的扩展能力。希望这篇文章对您有所帮助!