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