JWT 基本使用 #
安装 JWT 库 #
Node.js #
bash
npm install jsonwebtoken
Python #
bash
pip install PyJWT
Java #
xml
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
Go #
bash
go get github.com/golang-jwt/jwt/v5
生成 JWT #
Node.js 示例 #
javascript
const jwt = require('jsonwebtoken');
const payload = {
sub: 'user-123',
name: 'John Doe',
email: 'john@example.com',
role: 'admin'
};
const secret = 'your-256-bit-secret';
const token = jwt.sign(payload, secret, {
algorithm: 'HS256',
expiresIn: '1h',
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
subject: 'user-123',
jwtid: 'unique-token-id'
});
console.log(token);
Python 示例 #
python
import jwt
from datetime import datetime, timedelta
payload = {
'sub': 'user-123',
'name': 'John Doe',
'email': 'john@example.com',
'role': 'admin',
'iat': datetime.utcnow(),
'exp': datetime.utcnow() + timedelta(hours=1),
'iss': 'https://auth.example.com',
'aud': 'https://api.example.com'
}
secret = 'your-256-bit-secret'
token = jwt.encode(payload, secret, algorithm='HS256')
print(token)
Java 示例 #
java
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
public class JwtGenerator {
public static void main(String[] args) {
Algorithm algorithm = Algorithm.HMAC256("your-256-bit-secret");
String token = JWT.create()
.withIssuer("https://auth.example.com")
.withSubject("user-123")
.withAudience("https://api.example.com")
.withExpiresAt(new Date(System.currentTimeMillis() + 3600 * 1000))
.withClaim("name", "John Doe")
.withClaim("email", "john@example.com")
.withClaim("role", "admin")
.sign(algorithm);
System.out.println(token);
}
}
Go 示例 #
go
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
func main() {
secret := []byte("your-256-bit-secret")
claims := jwt.MapClaims{
"sub": "user-123",
"name": "John Doe",
"email": "john@example.com",
"role": "admin",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": time.Now().Add(time.Hour).Unix(),
"iat": time.Now().Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, _ := token.SignedString(secret)
fmt.Println(tokenString)
}
验证 JWT #
Node.js 示例 #
javascript
const jwt = require('jsonwebtoken');
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
const secret = 'your-256-bit-secret';
try {
const decoded = jwt.verify(token, secret, {
algorithms: ['HS256'],
issuer: 'https://auth.example.com',
audience: 'https://api.example.com'
});
console.log('Token is valid');
console.log(decoded);
} catch (err) {
console.error('Token verification failed:', err.message);
}
Python 示例 #
python
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
secret = 'your-256-bit-secret'
try:
decoded = jwt.decode(
token,
secret,
algorithms=['HS256'],
issuer='https://auth.example.com',
audience='https://api.example.com'
)
print('Token is valid')
print(decoded)
except jwt.ExpiredSignatureError:
print('Token has expired')
except jwt.InvalidTokenError as e:
print(f'Token is invalid: {e}')
Java 示例 #
java
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
public class JwtVerifier {
public static void main(String[] args) {
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
String secret = "your-256-bit-secret";
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("https://auth.example.com")
.withAudience("https://api.example.com")
.build();
DecodedJWT decoded = verifier.verify(token);
System.out.println("Token is valid");
System.out.println("Subject: " + decoded.getSubject());
System.out.println("Name: " + decoded.getClaim("name").asString());
} catch (JWTVerificationException e) {
System.err.println("Token verification failed: " + e.getMessage());
}
}
}
Go 示例 #
go
package main
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
)
func main() {
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
secret := []byte("your-256-bit-secret")
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return secret, nil
})
if err != nil {
fmt.Printf("Token verification failed: %v\n", err)
return
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
fmt.Println("Token is valid")
fmt.Printf("Subject: %v\n", claims["sub"])
fmt.Printf("Name: %v\n", claims["name"])
}
}
解析 JWT(不验证) #
Node.js 解析 #
javascript
const jwt = require('jsonwebtoken');
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
const decoded = jwt.decode(token);
console.log('Header:', decoded.header);
console.log('Payload:', decoded.payload);
const payload = jwt.decode(token, { complete: true });
console.log(payload);
Python 解析 #
python
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
header = jwt.get_unverified_header(token)
print('Header:', header)
payload = jwt.decode(token, options={'verify_signature': False})
print('Payload:', payload)
手动解析 #
javascript
function parseJwt(token) {
const parts = token.split('.');
if (parts.length !== 3) {
throw new Error('Invalid JWT format');
}
const header = JSON.parse(
Buffer.from(parts[0], 'base64').toString()
);
const payload = JSON.parse(
Buffer.from(parts[1], 'base64').toString()
);
return {
header,
payload,
signature: parts[2]
};
}
const parsed = parseJwt(token);
console.log(parsed);
JWT 选项详解 #
签名选项 #
text
┌─────────────────────────────────────────────────────────────┐
│ JWT 签名选项 │
├─────────────────────────────────────────────────────────────┤
│ │
│ algorithm 签名算法 │
│ ───────────────────────────────────────────────────────── │
│ - HS256, HS384, HS512 (HMAC) │
│ - RS256, RS384, RS512 (RSA) │
│ - ES256, ES384, ES512 (ECDSA) │
│ │
│ expiresIn 过期时间 │
│ ───────────────────────────────────────────────────────── │
│ - 数字:秒数 │
│ - 字符串:'1h', '2d', '7d' │
│ - 示例:expiresIn: '1h' │
│ │
│ notBefore 生效时间 │
│ ───────────────────────────────────────────────────────── │
│ - 延迟生效时间 │
│ - 示例:notBefore: '5m' │
│ │
│ issuer 签发者 │
│ ───────────────────────────────────────────────────────── │
│ - 标识签发者身份 │
│ - 示例:issuer: 'https://auth.example.com' │
│ │
│ subject 主题 │
│ ───────────────────────────────────────────────────────── │
│ - 标识用户 │
│ - 示例:subject: 'user-123' │
│ │
│ audience 受众 │
│ ───────────────────────────────────────────────────────── │
│ - 标识接收者 │
│ - 可以是字符串或数组 │
│ - 示例:audience: 'https://api.example.com' │
│ │
│ jwtid JWT ID │
│ ───────────────────────────────────────────────────────── │
│ - 唯一标识符 │
│ - 用于防重放 │
│ - 示例:jwtid: 'unique-token-id' │
│ │
│ keyid 密钥 ID │
│ ───────────────────────────────────────────────────────── │
│ - 标识使用的密钥 │
│ - 用于密钥轮换 │
│ - 示例:keyid: 'key-2024-01' │
│ │
└─────────────────────────────────────────────────────────────┘
验证选项 #
text
┌─────────────────────────────────────────────────────────────┐
│ JWT 验证选项 │
├─────────────────────────────────────────────────────────────┤
│ │
│ algorithms 允许的算法列表 │
│ ───────────────────────────────────────────────────────── │
│ - 必须明确指定 │
│ - 防止算法混淆攻击 │
│ - 示例:algorithms: ['RS256'] │
│ │
│ issuer 验证签发者 │
│ ───────────────────────────────────────────────────────── │
│ - 检查 iss 声明 │
│ - 示例:issuer: 'https://auth.example.com' │
│ │
│ audience 验证受众 │
│ ───────────────────────────────────────────────────────── │
│ - 检查 aud 声明 │
│ - 示例:audience: 'https://api.example.com' │
│ │
│ subject 验证主题 │
│ ───────────────────────────────────────────────────────── │
│ - 检查 sub 声明 │
│ - 示例:subject: 'user-123' │
│ │
│ clockTolerance 时钟容忍度 │
│ ───────────────────────────────────────────────────────── │
│ - 允许的时间偏差(秒) │
│ - 处理服务器时钟不同步 │
│ - 示例:clockTolerance: 10 │
│ │
│ maxAge 最大年龄 │
│ ───────────────────────────────────────────────────────── │
│ - Token 最大有效期 │
│ - 即使 exp 未过期 │
│ - 示例:maxAge: '1h' │
│ │
│ complete 返回完整信息 │
│ ───────────────────────────────────────────────────────── │
│ - 返回 header, payload, signature │
│ - 示例:complete: true │
│ │
└─────────────────────────────────────────────────────────────┘
使用 RSA 密钥 #
Node.js RSA 示例 #
javascript
const jwt = require('jsonwebtoken');
const fs = require('fs');
const privateKey = fs.readFileSync('private.pem');
const publicKey = fs.readFileSync('public.pem');
const payload = {
sub: 'user-123',
name: 'John Doe'
};
const token = jwt.sign(payload, privateKey, {
algorithm: 'RS256',
expiresIn: '1h'
});
console.log('Token:', token);
jwt.verify(token, publicKey, { algorithms: ['RS256'] }, (err, decoded) => {
if (err) {
console.error('Verification failed:', err.message);
return;
}
console.log('Decoded:', decoded);
});
Python RSA 示例 #
python
import jwt
with open('private.pem', 'r') as f:
private_key = f.read()
with open('public.pem', 'r') as f:
public_key = f.read()
payload = {
'sub': 'user-123',
'name': 'John Doe'
}
token = jwt.encode(payload, private_key, algorithm='RS256')
print('Token:', token)
decoded = jwt.decode(token, public_key, algorithms=['RS256'])
print('Decoded:', decoded)
错误处理 #
Node.js 错误类型 #
javascript
const jwt = require('jsonwebtoken');
try {
const decoded = jwt.verify(token, secret);
} catch (err) {
if (err.name === 'TokenExpiredError') {
console.error('Token has expired at:', err.expiredAt);
} else if (err.name === 'JsonWebTokenError') {
console.error('Invalid token:', err.message);
} else if (err.name === 'NotBeforeError') {
console.error('Token not active until:', err.date);
} else {
console.error('Unknown error:', err);
}
}
Python 错误类型 #
python
import jwt
from jwt import ExpiredSignatureError, InvalidTokenError
try:
decoded = jwt.decode(token, secret, algorithms=['HS256'])
except ExpiredSignatureError:
print('Token has expired')
except jwt.InvalidIssuerError:
print('Invalid issuer')
except jwt.InvalidAudienceError:
print('Invalid audience')
except jwt.ImmatureSignatureError:
print('Token not yet valid')
except InvalidTokenError as e:
print(f'Invalid token: {e}')
错误类型汇总 #
text
┌─────────────────────────────────────────────────────────────┐
│ JWT 错误类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ TokenExpiredError Token 已过期 │
│ ───────────────────────────────────────────────────────── │
│ - exp 声明时间已过 │
│ - 包含 expiredAt 属性 │
│ │
│ JsonWebTokenError 无效 Token │
│ ───────────────────────────────────────────────────────── │
│ - 签名验证失败 │
│ - 格式错误 │
│ - 算法不支持 │
│ │
│ NotBeforeError Token 未生效 │
│ ───────────────────────────────────────────────────────── │
│ - nbf 声明时间未到 │
│ - 包含 date 属性 │
│ │
│ InvalidIssuerError 无效签发者 │
│ ───────────────────────────────────────────────────────── │
│ - iss 声明验证失败 │
│ │
│ InvalidAudienceError 无效受众 │
│ ───────────────────────────────────────────────────────── │
│ - aud 声明验证失败 │
│ │
│ InvalidSubjectError 无效主题 │
│ ───────────────────────────────────────────────────────── │
│ - sub 声明验证失败 │
│ │
└─────────────────────────────────────────────────────────────┘
Express 中间件示例 #
认证中间件 #
javascript
const jwt = require('jsonwebtoken');
function authMiddleware(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ error: 'No token provided' });
}
const parts = authHeader.split(' ');
if (parts.length !== 2 || parts[0] !== 'Bearer') {
return res.status(401).json({ error: 'Invalid token format' });
}
const token = parts[1];
jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'],
issuer: 'https://auth.example.com'
}, (err, decoded) => {
if (err) {
return res.status(401).json({ error: 'Invalid token' });
}
req.user = decoded;
next();
});
}
app.get('/protected', authMiddleware, (req, res) => {
res.json({ message: 'Access granted', user: req.user });
});
角色检查中间件 #
javascript
function requireRole(role) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (req.user.role !== role) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}
app.delete('/admin/users/:id',
authMiddleware,
requireRole('admin'),
(req, res) => {
res.json({ message: 'User deleted' });
}
);
刷新 Token 机制 #
刷新流程 #
text
┌─────────────────────────────────────────────────────────────┐
│ 刷新 Token 流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ 客户端 │ │ 服务端 │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ │ 1. 登录 │ │
│ │─────────────────────────>│ │
│ │ │ │
│ │ 2. 返回 access_token │ │
│ │ 和 refresh_token │ │
│ │<─────────────────────────│ │
│ │ │ │
│ │ 3. 使用 access_token │ │
│ │─────────────────────────>│ │
│ │ │ │
│ │ 4. Token 过期 │ │
│ │<─────────────────────────│ │
│ │ │ │
│ │ 5. 使用 refresh_token │ │
│ │─────────────────────────>│ │
│ │ │ │
│ │ 6. 返回新的 access_token│ │
│ │<─────────────────────────│ │
│ │
└─────────────────────────────────────────────────────────────┘
实现示例 #
javascript
const jwt = require('jsonwebtoken');
const ACCESS_TOKEN_SECRET = 'access-secret';
const REFRESH_TOKEN_SECRET = 'refresh-secret';
function generateAccessToken(user) {
return jwt.sign(
{ sub: user.id, role: user.role },
ACCESS_TOKEN_SECRET,
{ expiresIn: '15m' }
);
}
function generateRefreshToken(user) {
return jwt.sign(
{ sub: user.id },
REFRESH_TOKEN_SECRET,
{ expiresIn: '7d' }
);
}
app.post('/login', (req, res) => {
const user = authenticateUser(req.body.username, req.body.password);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
res.json({
access_token: accessToken,
refresh_token: refreshToken,
expires_in: 900
});
});
app.post('/refresh', (req, res) => {
const { refresh_token } = req.body;
if (!refresh_token) {
return res.status(400).json({ error: 'Refresh token required' });
}
jwt.verify(refresh_token, REFRESH_TOKEN_SECRET, (err, decoded) => {
if (err) {
return res.status(401).json({ error: 'Invalid refresh token' });
}
const user = getUserById(decoded.sub);
if (!user) {
return res.status(401).json({ error: 'User not found' });
}
const accessToken = generateAccessToken(user);
res.json({
access_token: accessToken,
expires_in: 900
});
});
});
下一步 #
现在你已经掌握了 JWT 的基本使用方法,接下来学习 JWT 安全最佳实践,了解如何安全地使用 JWT!
最后更新:2026-03-28