Java教程

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

本文主要是介绍JWT学习:从零开始的JWT入门教程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文全面介绍了JWT的基本概念和使用方法,包括JWT的组成、工作原理以及如何生成和验证JWT。文章还探讨了JWT在实际应用中的应用场景和安全性考虑,并提供了具体的代码示例来帮助读者更好地理解和实践JWT学习。JWT学习不仅涵盖了JWT的基础知识,还涉及了实战演练和前后端集成的具体步骤。

JWT简介

什么是JWT

JWT (JSON Web Token) 是一种开放标准 (RFC 7519),用于在网络应用间安全地传输信息。JWT由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature)。JWT通常以.号分割的三个Base64字符串表示,例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT的主要特点包括:

  • 无状态:服务器端不需要存储会话信息,减轻了服务器的负担。
  • 安全性:通过数字签名保证数据的完整性和真实性。
  • 可扩展性:可以自由添加载荷数据,方便扩展。

JWT的工作原理

JWT的工作原理可以分为三个主要步骤:

  1. 创建JWT:客户端向服务器请求一个新的JWT,服务器根据密钥生成一个完整的JWT。
  2. 传输JWT:客户端将JWT传递给服务器,通常是在每次HTTP请求的头部。
  3. 验证JWT:服务器验证JWT的有效性,通过头和加密签名的匹配进行验证。

JWT的组成部分介绍

JWT由三部分组成:头部,载荷,签名。

  • 头部(Header):包含token类型(通常是JWT)和采用的加密算法(如HMAC、RSA等)。通常采用的加密算法包括HS256(使用密钥进行HMAC-SHA256加密)、RS256(使用RSA算法进行加密)等。
  • 载荷(Payload):载荷部分包含声明(Claims),声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:

    • Registered Claims:标准保留的声明,例如iss(发行者),exp(过期时间)。
    • Public Claims:自定义声明,通常包含用户信息(如ID、名称等)。
    • Private Claims:自定义声明,用于安全传输敏感数据。
  • 签名(Signature):通过头部指定的加密算法对头部和载荷的Base64编码后的字符串进行签名,确保数据的完整性。

JWT的应用场景

授权认证

JWT可以用于代替传统的session机制来进行用户认证。通过在客户端存储JWT,并在每次请求时发送JWT,服务器可以验证并获取用户信息,从而实现无状态认证。

import jwt
import time

# 用户登录逻辑
def authenticate(username, password):
    # 验证用户名和密码
    if username == 'admin' and password == 'admin':
        payload = {
            'sub': username,
            'iat': int(time.time()),
            'exp': int(time.time()) + 3600  # 1小时过期
        }
        token = jwt.encode(payload, 'secret', algorithm='HS256')
        return token
    else:
        return None

# 用户登录示例
token = authenticate('admin', 'admin')
print(token)

信息交换

JWT还可以用于安全的信息交换。例如,在微服务架构中,JWT可以用来在不同的服务之间传递用户信息,保障信息的安全性和一致性。

单点登录

JWT非常适合实现单点登录(Single Sign On,SSO)。通过在一个系统中登录后,生成JWT并传递给其他系统,避免用户多次登录。

def sso_login(token):
    try:
        decoded = jwt.decode(token, 'secret', algorithms=['HS256'])
        print(f"单点登录成功,用户ID: {decoded['sub']}")
    except jwt.ExpiredSignatureError:
        print("Token已过期")
    except jwt.InvalidTokenError:
        print("Token无效")

# 单点登录示例
sso_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
sso_login(sso_token)

JWT的基础概念

头部(Header)

头部包含两个字段,分别是typalg,用来表示token的类型和使用的加密算法。

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

Header通常会进行Base64编码。例如,上述头部经过Base64编码后的结果为:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

载荷(Payload)

载荷部分包含声明(Claims),是JWT的主要部分。声明可以分为三类:

  • Registered Claims:标准预留的声明字段。
  • Public Claims:自定义公共声明字段。
  • Private Claims:自定义私有声明字段。

以下是一个载荷的例子:

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

该载荷被Base64编码后,结果为:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

签名(Signature)

签名部分是通过使用头部指定的加密算法(如HS256)对头部和载荷的Base64编码后的字符串进行加密运算得到的。例如,如果使用HS256算法,并且密钥为secret,那么签名的计算过程如下:

  1. 将头部和载荷的Base64编码后的字符串拼接在一起。
  2. 使用密钥对拼接后的字符串进行HS256加密运算。
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  'secret')

签名部分的输出示例如下(注意这只是一个示例输出,实际结果会根据具体数据和密钥有所变化):

SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT的使用步骤

创建JWT

创建JWT需要三个步骤:准备头部、载荷、计算签名。

import jwt
import time

# 准备头部信息
header = {
    "typ": "JWT",
    "alg": "HS256"
}

# 准备载荷信息
payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": int(time.time())
}

# 生成token
secret = 'secret'  # 密钥
token = jwt.encode(payload, secret, algorithm='HS256')

print(token)

这段代码生成了一个标准的JWT,包含头部、载荷和签名。

验证JWT

验证JWT主要需要检查签名是否正确,以及载荷中的声明是否有效(如exp过期时间)。

import jwt
import time

# 假设收到的token是上面生成的token
received_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

# 验证token
try:
    decoded = jwt.decode(received_token, 'secret', algorithms=['HS256'])
    print(decoded)
except jwt.ExpiredSignatureError:
    print("Token已过期")
except jwt.InvalidTokenError:
    print("Token无效")

这个示例验证了JWT的有效性,并处理了过期的情况。

使用JWT进行用户认证

在实际应用中,通常会将JWT用于用户认证。当用户登录成功后,服务器会生成JWT并返回给客户端,客户端每次请求时携带该JWT。

import jwt
import time

# 用户登录逻辑
def authenticate_with_jwt(username, password):
    # 验证用户名和密码
    if username == 'admin' and password == 'admin':
        payload = {
            'sub': username,
            'iat': int(time.time()),
            'exp': int(time.time()) + 3600  # 1小时过期
        }
        token = jwt.encode(payload, 'secret', algorithm='HS256')
        return token
    else:
        return None

# 用户认证示例
token = authenticate_with_jwt('admin', 'admin')
print(token)

JWT的安全考虑

签名的重要性

签名是JWT的核心部分,用于保证数据的安全性和完整性。不使用签名的JWT将无法防止数据的篡改和伪造,因此非常重要。

def verify_signature(token):
    try:
        decoded = jwt.decode(token, 'secret', algorithms=['HS256'])
        print("签名有效")
    except jwt.ExpiredSignatureError:
        print("Token已过期")
    except jwt.InvalidSignatureError:
        print("无效签名")

# 签名验证示例
verify_signature("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")

选择合适的算法

选择合适的加密算法也很重要,常见的算法包括HS256(用于对称加密)、RS256(用于非对称加密)。选择什么算法取决于安全性需求和性能考量。

def generate_jwt_rsa(username):
    header = {"typ": "JWT", "alg": "RS256"}
    payload = {"sub": username, "iat": int(time.time())}
    private_key = open("path_to_private_key.pem", "rb").read()
    token = jwt.encode(payload, private_key, algorithm='RS256')
    return token

# 使用RS256算法生成的JWT
rsa_token = generate_jwt_rsa("admin")
print(rsa_token)

处理过期的JWT

JWT通常有一个exp(过期时间)声明,用于指定token的有效时间。如果JWT过期,客户端需要重新获取一个新token。服务器在验证JWT时,需要检查exp是否已经过期。

import jwt
import time

# 接收过期的token
received_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

# 验证token
try:
    decoded = jwt.decode(received_token, 'secret', algorithms=['HS256'])
    print(decoded)
except jwt.ExpiredSignatureError:
    print("Token已过期")
except jwt.InvalidTokenError:
    print("Token无效")
``

### 实战演练

#### 创建一个简单的JWT认证系统

本部分将实现一个简单的JWT认证系统,包括用户登录、获取token以及使用token验证请求。

##### 用户登录

用户登录时,服务器会验证用户名和密码,并生成JWT。

```python
import jwt
import time

def authenticate(username, password):
    # 验证用户名和密码
    if username == 'admin' and password == 'admin':
        payload = {
            'sub': username,
            'iat': int(time.time()),
            'exp': int(time.time()) + 3600  # 1小时过期
        }
        token = jwt.encode(payload, 'secret', algorithm='HS256')
        return token
    else:
        return None

# 用户登录示例
token = authenticate('admin', 'admin')
print(token)
使用JWT进行请求

用户在登录成功后,可以使用返回的JWT进行后续的请求。服务器在每次请求时,验证token的有效性。

import jwt

def verify_token(token):
    try:
        decoded = jwt.decode(token, 'secret', algorithms=['HS256'])
        print(f"认证成功,用户ID: {decoded['sub']}")
    except jwt.ExpiredSignatureError:
        print("Token已过期")
    except jwt.InvalidTokenError:
        print("Token无效")

# 模拟请求
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
verify_token(token)

实现用户登录与注销

用户登录后,服务器返回一个JWT,用户每发送一次请求就携带这个JWT。用户注销时,服务器需要清理相关资源,并返回一个无效的token。

def user_logout(token):
    try:
        decoded = jwt.decode(token, 'secret', algorithms=['HS256'])
        print("用户已成功注销")
    except jwt.ExpiredSignatureError:
        print("Token已过期")
    except jwt.InvalidTokenError:
        print("Token无效")

# 用户注销示例
logout_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
user_logout(logout_token)

验证前端与后端的JWT集成

为了验证前端和后端的JWT集成,我们可以搭建一个简单的前后端应用。

前端代码示例

前端可以使用JavaScript和Fetch API来发送请求,并在请求头中携带JWT。

fetch('/api/user', {
    method: 'GET',
    headers: {
        'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
    }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error))
后端代码示例

后端可以使用Python的Flask框架,实现JWT的验证。

from flask import Flask, request, jsonify
import jwt

app = Flask(__name__)

@app.route('/api/user')
def user():
    token = request.headers.get('Authorization')
    if not token:
        return jsonify({'error': '未提供Token'}), 401

    token = token.replace('Bearer ', '')
    try:
        decoded = jwt.decode(token, 'secret', algorithms=['HS256'])
        return jsonify({'message': '认证成功', 'user_id': decoded['sub']})
    except jwt.ExpiredSignatureError:
        return jsonify({'error': 'Token已过期'}), 401
    except jwt.InvalidTokenError:
        return jsonify({'error': 'Token无效'}), 401

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

通过以上代码实践,可以实现一个简单的JWT认证系统,并验证前后端的集成。

总结

JWT是一种用于在不同系统间安全传输信息的标准,它通过无状态的设计减轻了服务器的负担,并通过数字签名保证了数据的安全性和完整性。通过本文的学习,你已经掌握了JWT的基本概念、使用步骤以及安全考虑,希望对你在实际项目中的应用有所帮助。如果你需要更深入的学习,可以参考MooC网的相关课程。

这篇关于JWT学习:从零开始的JWT入门教程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!