当前位置: 首页 > 工具软件 > OAuth2-Server > 使用案例 >

Spring Oauth2-Authorization-Server JwtGenerator

谈禄
2023-12-01

Spring Oauth2-Authorization-Server JwtGenerator 使用

基于 spring-security-oauth2-authorization-server 0.2.3

JwtGenerator

顾名思义,使用 JwtEncoder 来生成 jwt 类型的 token

public final class JwtGenerator implements OAuth2TokenGenerator<Jwt> {
	private final JwtEncoder jwtEncoder;
	private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer;

	/**
	 * Constructs a {@code JwtGenerator} using the provided parameters.
	 *
	 * @param jwtEncoder the jwt encoder
	 */
	public JwtGenerator(JwtEncoder jwtEncoder) {
		Assert.notNull(jwtEncoder, "jwtEncoder cannot be null");
		this.jwtEncoder = jwtEncoder;
	}
}

JwtGenerator 是什么时候被创建的?

OAuth2ConfigurerUtils

static <B extends HttpSecurityBuilder<B>> OAuth2TokenGenerator<? extends OAuth2Token> getTokenGenerator(B builder) {
    OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator = builder.getSharedObject(OAuth2TokenGenerator.class);
    if (tokenGenerator == null) {
        tokenGenerator = getOptionalBean(builder, OAuth2TokenGenerator.class);
        if (tokenGenerator == null) {
            JwtGenerator jwtGenerator = getJwtGenerator(builder);
            OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
            OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer = getAccessTokenCustomizer(builder);
            if (accessTokenCustomizer != null) {
                accessTokenGenerator.setAccessTokenCustomizer(accessTokenCustomizer);
            }
            OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
            if (jwtGenerator != null) {
                tokenGenerator = new DelegatingOAuth2TokenGenerator(
                    jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
            } else {
                tokenGenerator = new DelegatingOAuth2TokenGenerator(
                    accessTokenGenerator, refreshTokenGenerator);
            }
        }
        builder.setSharedObject(OAuth2TokenGenerator.class, tokenGenerator);
    }
    return tokenGenerator;
}

private static <B extends HttpSecurityBuilder<B>> JwtGenerator getJwtGenerator(B builder) {
    JwtGenerator jwtGenerator = builder.getSharedObject(JwtGenerator.class);
    if (jwtGenerator == null) {
        JwtEncoder jwtEncoder = getJwtEncoder(builder);
        if (jwtEncoder != null) {
            jwtGenerator = new JwtGenerator(jwtEncoder);
            OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = getJwtCustomizer(builder);
            if (jwtCustomizer != null) {
                jwtGenerator.setJwtCustomizer(jwtCustomizer);
            }
            builder.setSharedObject(JwtGenerator.class, jwtGenerator);
        }
    }
    return jwtGenerator;
}

private static <B extends HttpSecurityBuilder<B>> JwtEncoder getJwtEncoder(B builder) {
    JwtEncoder jwtEncoder = builder.getSharedObject(JwtEncoder.class);
    if (jwtEncoder == null) {
        jwtEncoder = getOptionalBean(builder, JwtEncoder.class);
        if (jwtEncoder == null) {
            JWKSource<SecurityContext> jwkSource = getJwkSource(builder);
            if (jwkSource != null) {
                jwtEncoder = new NimbusJwsEncoder(jwkSource);
            }
        }
        if (jwtEncoder != null) {
            builder.setSharedObject(JwtEncoder.class, jwtEncoder);
        }
    }
    return jwtEncoder;
}

@SuppressWarnings("unchecked")
static <B extends HttpSecurityBuilder<B>> JWKSource<SecurityContext> getJwkSource(B builder) {
    JWKSource<SecurityContext> jwkSource = builder.getSharedObject(JWKSource.class);
    if (jwkSource == null) {
        ResolvableType type = ResolvableType.forClassWithGenerics(JWKSource.class, SecurityContext.class);
        jwkSource = getOptionalBean(builder, type);
        if (jwkSource != null) {
            builder.setSharedObject(JWKSource.class, jwkSource);
        }
    }
    return jwkSource;
}

在 getTokenGenerator 方法中:

  • getTokenGenerator
    • getJwtGenerator
      • getJwtEncoder
        • getJwkSource

由层级看出, 只要 IOC 容器 中有 JWKSource Bean, 那么就会自动装配 JwtGenerator

而 在JwtClientAssertionDecoderFactory 中:

private static NimbusJwtDecoder buildDecoder(RegisteredClient registeredClient) {
    JwsAlgorithm jwsAlgorithm = registeredClient.getClientSettings().getTokenEndpointAuthenticationSigningAlgorithm();
    if (jwsAlgorithm instanceof SignatureAlgorithm) {
        String jwkSetUrl = registeredClient.getClientSettings().getJwkSetUrl();
        return NimbusJwtDecoder.withJwkSetUri(jwkSetUrl).jwsAlgorithm((SignatureAlgorithm) jwsAlgorithm).build();
    }
    if (jwsAlgorithm instanceof MacAlgorithm) {
        String clientSecret = registeredClient.getClientSecret();
      
        SecretKeySpec secretKeySpec = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8),
                                                        JCA_ALGORITHM_MAPPINGS.get(jwsAlgorithm));
        return NimbusJwtDecoder.withSecretKey(secretKeySpec).macAlgorithm((MacAlgorithm) jwsAlgorithm).build();
    }
    throw new OAuth2AuthenticationException(oauth2Error);
}

对于 Jwt 加密算法中, 只有 SignatureAlgorithm 算法才会要求配置 jwkSetUrl,即

  • SignatureAlgorithm 会自动装配 JwtGenerator, 就会生成 JWT 类型的 token
  • MacAlgorithm 摘要算法则不会,自然生成的 token 也不会是 Jwt
 类似资料: