JWT 基础概念
JWT(JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在网络应用间安全地传输声明。一个 JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),通常格式为Header.Payload.Signature
。
Java 中 JWT 的简单实现
以下是一个简单的 Java JWT 实现示例,使用了 Nimbus JOSE + JWT 库:
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import net.minidev.json.JSONObject;
import java.text.ParseException;
import java.util.Date;
public class JWTExample {
// 密钥,实际应用中应妥善保管
private static final byte[] SECRET = "your-256-bit-secret-your-256-bit-secret".getBytes();
public static void main(String[] args) throws JOSEException, ParseException {
// 生成JWT
String jwt = generateToken();
System.out.println("生成的JWT: " + jwt);
// 验证JWT
boolean isValid = verifyToken(jwt);
System.out.println("JWT验证结果: " + isValid);
// 解析JWT
if (isValid) {
parseToken(jwt);
}
}
// 生成JWT
public static String generateToken() throws JOSEException {
// 创建JWS头,指定签名算法为HS256
JWSHeader header = new JWSHeader(JWSAlgorithm.HS256);
// 创建载荷
JSONObject payload = new JSONObject();
payload.put("sub", "user123");
payload.put("name", "John Doe");
payload.put("iat", new Date().getTime());
payload.put("exp", new Date(System.currentTimeMillis() + 3600 * 1000).getTime()); // 1小时后过期
// 创建JWS对象
JWSObject jwsObject = new JWSObject(header, new Payload(payload));
// 创建签名器
JWSSigner signer = new MACSigner(SECRET);
// 签名
jwsObject.sign(signer);
// 生成JWT字符串
return jwsObject.serialize();
}
// 验证JWT
public static boolean verifyToken(String jwt) throws JOSEException, ParseException {
// 解析JWT
JWSObject jwsObject = JWSObject.parse(jwt);
// 创建验证器
JWSVerifier verifier = new MACVerifier(SECRET);
// 验证签名
boolean isValid = jwsObject.verify(verifier);
// 验证过期时间
if (isValid) {
Date exp = new Date(jwsObject.getPayload().toJSONObject().getAsNumber("exp").longValue());
isValid = new Date().before(exp);
}
return isValid;
}
// 解析JWT
public static void parseToken(String jwt) throws ParseException {
JWSObject jwsObject = JWSObject.parse(jwt);
JSONObject payload = jwsObject.getPayload().toJSONObject();
System.out.println("解析JWT:");
System.out.println("Subject: " + payload.get("sub"));
System.out.println("Name: " + payload.get("name"));
System.out.println("Issued At: " + new Date(payload.getAsNumber("iat").longValue()));
System.out.println("Expiration Time: " + new Date(payload.getAsNumber("exp").longValue()));
}
}
要运行此代码,需要添加以下 Maven 依赖:
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.25.1</version>
</dependency>
进阶:Spring Boot 中集成 JWT
以下是一个在 Spring Boot 中集成 JWT 的示例,实现了基于 JWT 的认证和授权:
package com.example.demo.security;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtils {
@Value("${app.jwtSecret}")
private String jwtSecret;
@Value("${app.jwtExpirationMs}")
private int jwtExpirationMs;
// 生成JWT
public String generateJwtToken(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
return Jwts.builder()
.setSubject((userPrincipal.getUsername()))
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
// 从JWT中获取用户名
public String getUserNameFromJwtToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
// 验证JWT
public boolean validateJwtToken(String authToken) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
return true;
} catch (SignatureException e) {
System.out.println("Invalid JWT signature: {}", e.getMessage());
} catch (MalformedJwtException e) {
System.out.println("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
System.out.println("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
System.out.println("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("JWT claims string is empty: {}", e.getMessage());
}
return false;
}
}
高级:JWT 安全增强实践
- 使用 Refresh Token 机制:减少 AccessToken 的有效期,同时使用 Refresh Token 延长用户会话
// RefreshTokenService.java
public interface RefreshTokenService {
Optional<RefreshToken> findByToken(String token);
RefreshToken createRefreshToken(Long userId);
RefreshToken verifyExpiration(RefreshToken token);
int deleteByUserId(Long userId);
}
- JWT 与多因素认证结合
// 在生成JWT时添加多因素认证信息
public String generateJwtWithMfa(String username, boolean mfaVerified) {
Claims claims = Jwts.claims().setSubject(username);
claims.put("mfa_verified", mfaVerified);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
- 使用非对称加密:使用 RSA 或 ECDSA 算法代替 HMAC
// 生成RSA密钥对
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 使用私钥签名
String jwt = Jwts.builder()
.setSubject("user123")
.signWith(privateKey, SignatureAlgorithm.RS256)
.compact();
// 使用公钥验证
Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(jwt);
这些示例展示了 JWT 在 Java 中的不同应用场景,从基础的令牌生成和验证,到 Spring Boot 集成,再到安全增强实践。在实际应用中,应根据具体需求选择合适的实现方式,并注意密钥管理和安全防护。