文章目录
1. 为什么选择 ECDSA(椭圆曲线数字签名算法)
JWT Token 提供的签名算法有对称和非对称两种。通常在业务网关或微服务间的零信任场景下的 Token 验证,验证 Token 签名的密钥管理是主要问题。如果有其他方案能够提升对称加密密钥安全与验证签名性能,则可不考虑使用非对成加密算法进行签名。使用 ECDSA 有以下优势:
- 非对称加密算法相较于对称加密算法密钥管理安全度更高;
- ECDSA 相较于 RSA 相同的安全级别使用的密钥更短,相反使用较长的密钥 ECDSA 的安全度更高;
- ECDSA 相较于 RSA 所需计算资源更少;
2. 生成签名公私钥
2.1. 使用 Open SSL 生成公私钥
openssl ecparam -genkey -name secp521r1 -out ./crt/access-token-ec-private-key.pem
openssl ec -in ./crt/access-token-ec-private-key.pem -pubout -out ./crt/access-token-ec-public-key.pem
2.2. Java 语言 pkcs8 格式私钥转换
openssl pkcs8 -topk8 -inform pem -in ./crt/access-token-ec-private-key.pem -outform pem -nocrypt -out ./crt/access-token-ec-private-key-pkcs8.pem
3. SpringBoot 分环境配置密钥
3.1. yaml 文件配置
token:
access:
publicKey: '粘贴公钥'
privateKey: '粘贴私钥'
3.2. 密钥配置类
@Configuration
public class JWTSecretConfigure {
private static final String ALGORITHM = "EC";
@Value("${token.access.privateKey}")
private String accessTokenECPrivateKey;
@Value("${token.access.publicKey}")
private String accessTokenECPublicKey;
@Bean("AccessTokenECPrivateKey")
public ECPrivateKey createAccessTokenECPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance(ALGORITHM);
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(accessTokenECPrivateKey));
return (ECPrivateKey) kf.generatePrivate(keySpec);
}
@Bean("AccessTokenECPublicKey")
public ECPublicKey createAccessTokenECPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance(ALGORITHM);
EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(accessTokenECPublicKey));
return (ECPublicKey) kf.generatePublic(keySpec);
}
}
4. 使用 auth0 生成 JWT Token
4.1. 依赖
<properties>
<auth0-jwt.version>3.6.0</auth0-jwt.version>
</properties>
<dependencies>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${auth0-jwt.version}</version>
</dependency>
</dependencies>
4.2. 生成 Token
// 注入密钥
@Resource(name = "AccessTokenECPrivateKey")
private ECPrivateKey accessTokenECPrivateKey;
@Resource(name = "AccessTokenECPublicKey")
private ECPublicKey accessTokenECPublicKey;
// 生成 Token
Algorithm algorithm = Algorithm.ECDSA512(accessTokenECPublicKey, accessTokenECPrivateKey);
String accessToken = JWT.create()
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRES))
.withIssuedAt(new Date())
.withIssuer(ISSUER)
.sign(algorithm);
5. 注意事项
- 在要求性能场景下需要做好基准测试,评估使用 ECDSA 签名算法签发 Token 的性能是否符合要求。
- 非对称加密算法相对于对称加密算法管理密钥安全性有提升,但请注意私钥仅在签发 Token 的服务中使用,且定期更换。
- 基于配置文件的密钥管理请确保配置文件网络传输加密且配置有白名单或其他访问配置文件的认证方式。