JWT生成
- 密钥管理:使用强加密算法生成的长密钥,例如使用
openssl rand -base64 64
生成64字节的Base64编码密钥。该密钥需严格保密,可存储在安全的密钥管理系统(如HashiCorp Vault)中。
- 负载信息:在JWT的负载(Payload)中包含必要的用户信息,如用户ID、用户名、角色等。同时添加一些元数据,如过期时间(
exp
)、颁发时间(iat
)等。例如:
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"exp": 1689446400,
"iat": 1689360000
}
- 签名算法:选择合适的签名算法,如HS256(对称加密)或RS256(非对称加密)。对于大规模分布式系统,RS256更适合,因为它支持密钥的分布式管理。使用Java的
jjwt
库生成JWT示例如下:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
public class JwtUtil {
private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public static String generateToken(String subject, String role, long expiration) {
Date now = new Date();
Date expirationDate = new Date(now.getTime() + expiration);
Claims claims = Jwts.claims().setSubject(subject);
claims.put("role", role);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expirationDate)
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
}
JWT存储
- 客户端存储:在前端应用中,JWT可存储在
HttpOnly
的Cookie中,以防止XSS攻击窃取JWT。也可以存储在LocalStorage或SessionStorage中,但需要注意安全性,避免被脚本获取。例如,使用JavaScript设置 HttpOnly
Cookie:
document.cookie = "jwtToken=" + token + ";path=/;HttpOnly";
- 服务器端存储:对于一些需要额外验证或管理的场景,服务器端可以将JWT的元数据(如用户ID、过期时间等)存储在分布式缓存中,如Redis。这样可以快速查询JWT的状态,如是否已注销等。示例代码如下(使用Java Redis客户端Jedis):
import redis.clients.jedis.Jedis;
public class JwtRedisUtil {
private static final String JWT_PREFIX = "jwt:";
public static void storeJwtMetadata(String userId, String jwtToken, long expiration) {
try (Jedis jedis = new Jedis("localhost", 6379)) {
jedis.setex(JWT_PREFIX + userId, (int) (expiration / 1000), jwtToken);
}
}
public static String getJwtMetadata(String userId) {
try (Jedis jedis = new Jedis("localhost", 6379)) {
return jedis.get(JWT_PREFIX + userId);
}
}
}
JWT传输
- HTTP Headers:在客户端与服务端交互时,将JWT放在
Authorization
头中,格式为 Bearer <token>
。例如,在HTTP请求中添加头信息:
GET /api/resource HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjg5NDQ2NDAwLCJpYXQiOjE2ODkzNjAwMDB9.NXjZ3f4m98746nJ01c8g798432768945
- 加密传输:使用HTTPS协议进行通信,确保JWT在传输过程中的保密性和完整性,防止中间人攻击篡改JWT。
JWT验证流程优化
- 分布式缓存加速:在验证JWT时,可以先从分布式缓存(如Redis)中查询JWT的元数据,判断JWT是否有效、是否已注销等。如果缓存中没有相关信息,再进行完整的JWT验证流程。这样可以减少JWT验证的计算开销。
- 批量验证:对于一些需要同时验证多个JWT的场景(如批量请求),可以实现批量验证机制,减少重复的验证操作,提高验证效率。例如,将多个JWT收集到一个列表中,一次性传递给验证方法进行验证。
- 缓存验证结果:对于频繁访问的资源,可以将JWT的验证结果缓存起来,在一定时间内(如短时间内频繁请求同一资源)直接使用缓存的验证结果,避免重复验证。
与不同微服务的集成方式
- 网关层验证:在API网关(如Spring Cloud Gateway、Zuul等)中统一进行JWT验证。网关接收到请求后,先验证JWT的有效性,然后根据JWT中的角色信息进行权限判断,决定是否将请求转发到后端微服务。示例配置如下(Spring Cloud Gateway):
spring:
cloud:
gateway:
routes:
- id: service1
uri: lb://service1
predicates:
- Path=/service1/**
filters:
- name: JwtFilter
args:
authenticationManager: jwtAuthenticationManager
secureRoutes: true
- 微服务内部验证:除了网关层验证,每个微服务也可以在内部进行二次验证,确保请求的安全性。微服务可以通过共享的JWT验证库来验证JWT的有效性和权限。例如,在Spring Boot微服务中,可以使用
jjwt
库编写一个切面(Aspect)来验证JWT:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
@Aspect
@Component
public class JwtAspect {
private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
@Around("@annotation(io.github.jwtauthentication.JwtSecured)")
public Object verifyJwt(ProceedingJoinPoint joinPoint) throws Throwable {
String jwtToken = getJwtFromRequest();
Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(jwtToken)
.getBody();
String role = (String) claims.get("role");
// 权限判断
if (!"admin".equals(role)) {
throw new RuntimeException("Access denied");
}
return joinPoint.proceed();
}
private String getJwtFromRequest() {
// 从请求头中获取JWT的逻辑
return null;
}
}
- 跨微服务传递:当一个微服务需要调用另一个微服务时,将JWT从调用方微服务传递到被调用方微服务。可以通过在HTTP请求头中传递JWT,被调用方微服务在接收到请求后进行验证。这样可以确保整个分布式系统中的认证和授权的一致性。