spring-security-oauth2-jose 模块的一些 DEMO
前言
Spring Security 提供了对 OAuth2 的支持,该包下提供 4 个模块:
oauth2-core ,基础核心模块oauth2-jose ,JOSE:Javascript Object Signing and Encryption ,对应 JWS JWE 的实现oauth2-client ,oauth2 client 组件的实现oauth2-resource-server ,oauth2 resource server 组件的实现
本文是基于 oauth2-jose 模块的一些 demo 展示,对应依赖 spring-securty-oauth2-jose
Nimbus
Nimbus 应该是目前最好用的 JWT API 了,spring-security-oauth2-jose 也是基于 Nimbus API 的封装
demo
RSA256
@Test
public void rs256() throws JOSEException, ParseException, InterruptedException {
RSAKey rsaKey = new RSAKeyGenerator(2048)
.generate();
RSAKey publicJWK = rsaKey.toPublicJWK();
String publicJWKJson = publicJWK.toJSONString();
JWSSigner signer = new RSASSASigner(rsaKey);
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet.Builder()
.expirationTime(new Date(new Date().getTime() + 5 * 1000))
.audience("xsn")
.build();
SignedJWT signedJWT = new SignedJWT(
new JWSHeader(JWSAlgorithm.RS256)
, jwtClaimsSet
);
signedJWT.sign(signer);
String jwt = signedJWT.serialize();
SignedJWT parse = SignedJWT.parse(jwt);
JWSVerifier verifier = new RSASSAVerifier(
RSAKey.parse(publicJWKJson)
);
boolean verify = parse.verify(verifier);
if (verify) {
System.out.println(parse.getJWTClaimsSet().getAudience());
}
}
RSA256 应该是最常用的 JWS 算法,一般地:认证中心基于该算法加签,客户端则基于对应的 公钥 验签Nimbus 提供开箱即用的 API 生成 RSAKey - 可以基于
JWTClaimsSet Builder API 轻松的构造 JWT 的信息,它还定义了一些默认的属性比如 issuer subject expireTime 等 - 上述
demo 包含基于 RSA256 的 加签 和 验签
HS256
@Test
public void hs256() throws JOSEException, ParseException {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[32];
random.nextBytes(bytes);
JWSSigner signer = new MACSigner(bytes);
JWSObject jwt = new JWSObject(
new JWSHeader(JWSAlgorithm.HS256)
, new Payload("hello jwt")
);
jwt.sign(signer);
String serialize = jwt.serialize();
JWSObject parse = JWSObject.parse(serialize);
JWSVerifier verifier = new MACVerifier(bytes);
boolean verify = parse.verify(verifier);
if (verify) {
System.out.println(parse.getPayload());
}
}
- 对称密钥算法
HS256 - 大致过程与
RSA256 类似
JWKMatcher
@Test
public void jwkMatcher() throws JOSEException {
JWK jwk1 = new RSAKey.Builder(new RSAKeyGenerator(2048).generate())
.keyID("id1")
.keyOperations(new HashSet<KeyOperation>() {{ add(KeyOperation.SIGN); }})
.build();
JWK jwk2 = new RSAKey.Builder(new RSAKeyGenerator(2048).generate())
.keyID("id1")
.keyOperations(new HashSet<KeyOperation>() {{ add(KeyOperation.ENCRYPT); }})
.build();
JWK jwk3 = new RSAKey.Builder(new RSAKeyGenerator(2048).generate())
.keyID("id3")
.keyOperations(new HashSet<KeyOperation>() {{ add(KeyOperation.ENCRYPT); }})
.build();
JWKSet jwkSet = new JWKSet(new ArrayList<JWK>() {{
add(jwk1);
add(jwk2);
add(jwk3);
}});
JWKMatcher matcher1 = new JWKMatcher.Builder()
.keyID("id1")
.build();
JWKMatcher matcher2 = new JWKMatcher.Builder()
.keyOperations(KeyOperation.SIGN)
.build();
List<JWK> select1 = new JWKSelector(matcher1).select(jwkSet);
List<JWK> select2 = new JWKSelector(matcher2).select(jwkSet);
select1.forEach(System.out::println);
System.out.println("----");
select2.forEach(System.out::println);
}
JWK ,Json Web Key ,比如 RSAKey JWKSet ,JWK 的集合封装JWKMatcher 则是基于 keyID keyOperation 等属性从 JWKSet 中匹配对应的 JWK 集合
spring-security-oauth2-jose
spring-security-oauth2-jose 底层依赖 Nimbus ,主要封装了两个大的 API :
JwtEncoder ,负责对 JWT 编码(JWS 或 JWE )JwtDecoder ,负责 JWT 的解码
demo
@Test
public void rs256() throws JOSEException, InterruptedException {
RSAKey rsaKey = new RSAKeyGenerator(2048).generate();
JwtEncoder encoder = new NimbusJwtEncoder(
new ImmutableJWKSet<>(
new JWKSet(rsaKey)
)
);
Jwt jwt = encoder.encode(JwtEncoderParameters.from(
JwsHeader.with(SignatureAlgorithm.RS256)
.build()
, JwtClaimsSet.builder()
.expiresAt(Instant.now().plusSeconds(5))
.subject("xsn")
.claim("content", "hello spring jwt")
.build()
)
);
String tokenValue = jwt.getTokenValue();
DefaultJWTProcessor<SecurityContext> processor = new DefaultJWTProcessor<>();
processor.setJWSKeySelector(new JWSVerificationKeySelector<SecurityContext>(
JWSAlgorithm.RS256
, new ImmutableJWKSet<>(new JWKSet(rsaKey.toPublicJWK()))
));
JwtDecoder decoder = new NimbusJwtDecoder(processor);
Jwt decode = decoder.decode(tokenValue);
System.out.println(decode.getClaim(JwtClaimNames.SUB).toString());
System.out.println(decode.getClaim("content").toString());
}
- 示例中是基于
RSA256 算法的 加签 验签 过程 DefaultJWTProcessor 包含对 JWT 过期时间的校验,对应 JwtClaimNames 的 expireTime 属性,比如示例中的 JWT 有效期为 5s
总结
这些 API 一般可能不会直接使用,是 Spring Security 对 OAuth2 JWT 的核心支持
完整 demo 示例
|