为了账号安全,请及时绑定邮箱和手机立即绑定

从零开始学习JWT:入门教程

JWT(JSON Web Token)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在网络通信中安全地传输信息。在本教程中,我们将从JWT的基本概念开始,逐步介绍其工作原理、生成和验证方法,以及如何在实际应用中使用JWT。通过Python和JavaScript示例,读者可以直观地了解JWT的工作流程。JWT的使用能够提高系统的安全性,减少服务器端的内存开销。

1. JWT简介

1.1 什么是JWT

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在网络中安全地传输信息。JWT主要包含三部分内容:头部(Header)、有效载荷(Payload)和签名(Signature)。这三个部分通过Base64编码后连接在一起,形成了一个完整的JWT字符串。

1.2 JWT的工作原理

JWT的工作原理可以分为以下几个步骤:

  1. 生成JWT

    • Header:包含令牌的类型(例如,JWT)和所使用的签名算法(例如,HMAC SHA256或RSA)。
    • Payload:包含声明(claims),声明是关于实体(通常是用户)和其他数据的声明。声明可以被分为三类:内置声明、公共声明和私有声明。
    • Signature:生成签名以验证令牌的完整性和真实性。
  2. 传输JWT

    • 生成的JWT通常通过HTTP请求头中的Authorization字段传输,格式为Bearer <token>
  3. 验证JWT
    • 验证签名以确保令牌未被篡改。
    • 检查令牌的过期时间(如果存在)以确保其有效性。

1.3 JWT的优势与应用场景

优势

  • 简洁性:JWT的格式简洁,易于传输。
  • 状态性:无需服务器端存储会话,减少了服务器的内存开销。
  • 安全性:通过签名确保了完整性和不可篡改性。

应用场景

  • 身份验证:实现无状态的认证机制。
  • 授权:在客户端和服务器之间传递授权信息。
  • 跨域共享:便于跨域共享用户信息。
  • API安全:保护API接口不受未授权访问。
2. JWT的组成部分

JWT由三个部分组成:头部(Header)、有效载荷(Payload)和签名(Signature)。这三个部分通过Base64编码后连接在一起,形成了一个完整的JWT字符串。

2.1 Header

JWT的头部包含两个部分:令牌类型和加密算法。这是一个JSON对象,然后通过Base64编码。

{
  "alg": "HS256",
  "typ": "JWT"
}

这里,alg 代表加密算法(如HS256),typ 代表令牌类型(如JWT)。

2.2 Payload

有效载荷包含声明(Claims),这些声明是关于实体(通常为用户)和其他数据的声明。这些声明可以是标准的、公共的或私有的。

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
  • sub:主体,即用户的唯一标识。
  • name:用户的姓名。
  • iat:声明的时间,具体到秒。

2.3 Signature

签名确保了JWT的完整性和不可篡改性。签名是通过将头部和有效载荷Base64编码后的字符串与密钥一起使用加密算法生成的。

签名的生成方式如下:

import base64
import hmac
import hashlib

def generate_signature(header_b64, payload_b64, secret):
    signature_input = f"{header_b64}.{payload_b64}"
    signature = hmac.new(
        secret.encode('utf-8'), 
        signature_input.encode('utf-8'), 
        hashlib.sha256
    ).digest()
    return base64.urlsafe_b64encode(signature).decode('utf-8')

header = {
    "alg": "HS256",
    "typ": "JWT"
}

payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": 1516239022
}

header_b64 = base64.urlsafe_b64encode(json.dumps(header, separators=(',', ':')).encode('utf-8')).decode('utf-8')
payload_b64 = base64.urlsafe_b64encode(json.dumps(payload, separators=(',', ':')).encode('utf-8')).decode('utf-8')
secret = "secret"

signature = generate_signature(header_b64, payload_b64, secret)
3. 如何生成JWT

生成JWT的方法有很多,这里我们将通过Python和JavaScript两种方式来生成JWT。

3.1 使用Python库生成JWT

Python中,可以使用PyJWT库来生成JWT。

import jwt
import datetime

# 创建头部
header = {
    "alg": "HS256",
    "typ": "JWT"
}

# 创建payload
payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": datetime.datetime.utcnow(),
    "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=10)
}

# 生成JWT
secret = "secret"
token = jwt.encode(payload, secret, algorithm="HS256")
print("Generated JWT:", token)

3.2 使用JavaScript库生成JWT

在JavaScript中,可以使用jsonwebtoken库来生成JWT。

const jwt = require('jsonwebtoken');

// 创建头部
const header = {
    alg: "HS256",
    typ: "JWT"
};

// 创建payload
const payload = {
    sub: "1234567890",
    name: "John Doe",
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + 600
};

// 生成JWT
const secret = "secret";
const token = jwt.sign(payload, secret, { algorithm: 'HS256' });
console.log("Generated JWT:", token);
4. 如何验证JWT

验证JWT的过程包括验证签名和验证有效载荷。

4.1 验证签名

签名的验证确保了JWT未被篡改。验证签名需要使用相同的密钥和算法。

Python示例

import jwt

# 验证JWT
try:
    decoded_token = jwt.decode(token, secret, algorithms=["HS256"])
    print("Valid JWT:", decoded_token)
except jwt.ExpiredSignatureError:
    print("Token is expired")
except jwt.InvalidTokenError:
    print("Invalid token")

JavaScript示例

const jwt = require('jsonwebtoken');

// 验证JWT
try {
    const decoded_token = jwt.verify(token, secret, { algorithms: ['HS256'] });
    console.log("Valid JWT:", decoded_token);
} catch (error) {
    if (error.name === 'TokenExpiredError') {
        console.log("Token is expired");
    } else {
        console.log("Invalid token");
    }
}

4.2 验证有效载荷

验证有效载荷主要是检查JWT的有效负载中的声明(claims)。例如,可以验证过期时间(exp)是否已过期。

Python示例

import jwt

# 验证JWT过期时间
try:
    decoded_token = jwt.decode(token, secret, algorithms=["HS256"])
    if decoded_token['exp'] < datetime.datetime.now().timestamp():
        print("Token has expired")
    else:
        print("Valid JWT:", decoded_token)
except jwt.ExpiredSignatureError:
    print("Token is expired")
except jwt.InvalidTokenError:
    print("Invalid token")

JavaScript示例

const jwt = require('jsonwebtoken');

// 验证JWT过期时间
try {
    const decoded_token = jwt.verify(token, secret, { algorithms: ['HS256'] });
    if (decoded_token.exp < Math.floor(Date.now() / 1000)) {
        console.log("Token has expired");
    } else {
        console.log("Valid JWT:", decoded_token);
    }
} catch (error) {
    if (error.name === 'TokenExpiredError') {
        console.log("Token is expired");
    } else {
        console.log("Invalid token");
    }
}
5. JWT的存储与使用

5.1 如何存储JWT

JWT可以存储在客户端的本地存储中,如localStoragesessionStorage,也可以存储在cookies中。存储JWT时,需要注意安全性,避免存储在容易被攻击的地方。

HTML示例

<script>
    // 存储JWT到localStorage
    localStorage.setItem('token', 'your_jwt_token_here');
    // 从localStorage中获取JWT
    const token = localStorage.getItem('token');
    console.log("Token from localStorage:", token);
</script>

5.2 如何使用JWT进行身份验证

在前后端分离的项目中,可以使用JWT进行身份验证。前端在每次请求时携带JWT,后端通过验证JWT来确认用户身份。

Python示例

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/protected')
def protected():
    token = request.headers.get('Authorization', None)
    if not token:
        return jsonify({"message": "Missing token"}), 401
    try:
        decoded_token = jwt.decode(token, secret, algorithms=["HS256"])
        return jsonify({"message": "Access granted", "user": decoded_token}), 200
    except jwt.ExpiredSignatureError:
        return jsonify({"message": "Token is expired"}), 401
    except jwt.InvalidTokenError:
        return jsonify({"message": "Invalid token"}), 401

if __name__ == '__main__':
    app.run()

JavaScript示例

const fetch = require('node-fetch');

// 使用JWT访问受保护的资源
fetch('/protected', {
    headers: {
        'Authorization': 'Bearer your_jwt_token_here'
    }
}).then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));
6. JWT的注意事项

6.1 有效载荷大小限制

有效载荷大小受限,因为JWT需要被Base64编码和传输。一般推荐的有效载荷大小限制在1KB以内。例如,如下代码展示了如何生成一个较小的payload。

import jwt

# 创建payload
payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": int(time.time())
}

# 生成JWT
token = jwt.encode(payload, secret, algorithm="HS256")
print("Generated JWT:", token)

6.2 签名密钥的重要性

签名密钥是JWT的核心,它用于生成和验证签名。一旦密钥泄露,任何人都可以生成有效的JWT,因此必须确保密钥的保密性。例如,以下代码展示了如何生成和验证JWT时使用安全的密钥。

import jwt
import os

# 生成密钥
secret = os.urandom(24).hex()

# 生成JWT
payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": int(time.time())
}
token = jwt.encode(payload, secret, algorithm="HS256")
print("Generated JWT:", token)

# 验证JWT
try:
    decoded_token = jwt.decode(token, secret, algorithms=["HS256"])
    print("Valid JWT:", decoded_token)
except jwt.ExpiredSignatureError:
    print("Token is expired")
except jwt.InvalidTokenError:
    print("Invalid token")

6.3 安全性考虑

  • 传输安全:JWT应该通过HTTPS传输,以防止中间人攻击。
  • 存储安全:避免将JWT存储在容易被攻击的地方,如本地存储。例如,下面的代码展示了如何安全地存储JWT。
from flask import Flask, session

app = Flask(__name__)

@app.route('/login')
def login():
    # 模拟登录
    session['jwt_token'] = 'your_jwt_token_here'
    return jsonify({"message": "Login successful"}), 200

@app.route('/protected')
def protected():
    token = session.get('jwt_token', None)
    if not token:
        return jsonify({"message": "Missing token"}), 401
    try:
        decoded_token = jwt.decode(token, secret, algorithms=["HS256"])
        return jsonify({"message": "Access granted", "user": decoded_token}), 200
    except jwt.ExpiredSignatureError:
        return jsonify({"message": "Token is expired"}), 401
    except jwt.InvalidTokenError:
        return jsonify({"message": "Invalid token"}), 401

if __name__ == '__main__':
    app.run()
  • 密钥管理:确保密钥的保密性和安全性。
  • 过期时间:合理设置JWT的有效期,以减少泄露的风险。
  • 黑名单管理:在某些情况下,需要维护一个黑名单,以便在JWT被泄露后阻止其使用。

通过以上详细步骤,我们可以看到JWT在现代Web开发中的重要性和应用。从生成到存储,再到验证,每个环节都需要谨慎处理以确保安全性。希望本文能帮助你更好地理解和使用JWT。

总结
本文介绍了JWT的基本概念、生成和验证方法,以及在实际应用中的使用方式。通过Python和JavaScript示例,读者可以直观地了解JWT的工作流程。在实际项目中,合理使用JWT可以提高系统的安全性,减少服务器端的内存开销,实现更高效的用户认证和授权。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消