Spring Oauth2-Authorization-Server中OAuth2TokenGenerator 生成

Spring Oauth2-Authorization-Server OAuth2TokenGenerator token生成

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

OAuth2TokenGenerator

@FunctionalInterface
public interface OAuth2TokenGenerator<T extends OAuth2Token> {

	/**
	 * Generate an OAuth 2.0 Token using the attributes contained in the {@link OAuth2TokenContext},
	 * or return {@code null} if the {@link OAuth2TokenContext#getTokenType()} is not supported.
	 *
	 * <p>
	 * If the returned {@link OAuth2Token} has a set of claims, it should implement {@link ClaimAccessor}
	 * in order for it to be stored with the {@link OAuth2Authorization}.
	 *
	 * @param context the context containing the OAuth 2.0 Token attributes
	 * @return an {@link OAuth2Token} or {@code null} if the {@link OAuth2TokenContext#getTokenType()} is not supported
	 */
	@Nullable
	T generate(OAuth2TokenContext context);

}

目前有几种实现:

  • OAuth2RefreshTokenGenerator
  • OAuth2AccessTokenGenerator: 当 OAuth2TokenFormat.REFERENCE “reference” 时 生成token 规则
  • JwtGenerator: 当 OAuth2TokenFormat 为 OAuth2TokenFormat.SELF_CONTAINED

服务器端生成的token 格式有:

  • OAuth2TokenFormat.REFERENCE
  • OAuth2TokenFormat.SELF_CONTAINED: 加密,如JWT, 默认,需要提供JWK

JwtGenerator

生成的token 为Jwt 方式

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;
    }

    @Nullable
    @Override
    public Jwt generate(OAuth2TokenContext context) {
        if (context.getTokenType() == null ||
            (!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) &&
             !OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue()))) {
            return null;
        }
        if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) &&
            !OAuth2TokenFormat.SELF_CONTAINED
            .equals(context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
            return null;
        }
        //...omit
        Jwt jwt = this.jwtEncoder.encode(headers, claims);

        return jwt;
    }

}

这里的 JwtEncoder 默认使用 SignatureAlgorithm.RS256

默认的tokenSetting:

public static Builder builder() {
    return new Builder()
        .accessTokenTimeToLive(Duration.ofMinutes(5))
        .accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
        .reuseRefreshTokens(true)
        .refreshTokenTimeToLive(Duration.ofMinutes(60))
        .idTokenSignatureAlgorithm(SignatureAlgorithm.RS256);
}

如果要生成 Jwt, 就需要提供JWK 获取方式,如:

@Bean
public JWKSource<SecurityContext> jwkSource() {
    RSAKey rsaKey = Jwks.generateRsa();
    JWKSet jwkSet = new JWKSet(rsaKey);
    return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}

如上配置, 在 oauth2 客户端就可以通过 默认的 /oauth2/jwks 获取解密密钥, 在 NimbusJwkSetEndpointFilter

public final class NimbusJwkSetEndpointFilter extends OncePerRequestFilter {
    /**
	 * The default endpoint {@code URI} for JWK Set requests.
	 */
    private static final String DEFAULT_JWK_SET_ENDPOINT_URI = "/oauth2/jwks";

    private final JWKSource<SecurityContext> jwkSource;
    private final JWKSelector jwkSelector;
    private final RequestMatcher requestMatcher;

    /**
	 * Constructs a {@code NimbusJwkSetEndpointFilter} using the provided parameters.
	 * @param jwkSource the {@code com.nimbusds.jose.jwk.source.JWKSource}
	 */
    public NimbusJwkSetEndpointFilter(JWKSource<SecurityContext> jwkSource) {
        this(jwkSource, DEFAULT_JWK_SET_ENDPOINT_URI);
    }

    /**
	 * Constructs a {@code NimbusJwkSetEndpointFilter} using the provided parameters.
	 *
	 * @param jwkSource the {@code com.nimbusds.jose.jwk.source.JWKSource}
	 * @param jwkSetEndpointUri the endpoint {@code URI} for JWK Set requests
	 */
    public NimbusJwkSetEndpointFilter(JWKSource<SecurityContext> jwkSource, String jwkSetEndpointUri) {
        Assert.notNull(jwkSource, "jwkSource cannot be null");
        Assert.hasText(jwkSetEndpointUri, "jwkSetEndpointUri cannot be empty");
        this.jwkSource = jwkSource;
        this.jwkSelector = new JWKSelector(new JWKMatcher.Builder().build());
        this.requestMatcher = new AntPathRequestMatcher(jwkSetEndpointUri, HttpMethod.GET.name());
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

        if (!this.requestMatcher.matches(request)) {
            filterChain.doFilter(request, response);
            return;
        }

        JWKSet jwkSet;
        try {
            jwkSet = new JWKSet(this.jwkSource.get(this.jwkSelector, null));
        }
        catch (Exception ex) {
            throw new IllegalStateException("Failed to select the JWK(s) -> " + ex.getMessage(), ex);
        }

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        try (Writer writer = response.getWriter()) {
            writer.write(jwkSet.toString());	// toString() excludes private keys
        }
    }
}

OAuth2AccessTokenGenerator

默认是Base64 生成的token:

public final class OAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OAuth2AccessToken> {
	private final StringKeyGenerator accessTokenGenerator =
			new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96);
	private OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer;

	@Nullable
	@Override
	public OAuth2AccessToken generate(OAuth2TokenContext context) {
        
        // 必须是 OAuth2TokenFormat.REFERENCE 的token 格式
		if (!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) ||
				!OAuth2TokenFormat.REFERENCE
            .equals(context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
			return null;
		}

	   //omit...
		OAuth2TokenClaimsSet accessTokenClaimsSet = claimsBuilder.build();

		OAuth2AccessToken accessToken = new OAuth2AccessTokenClaims(OAuth2AccessToken.TokenType.BEARER,
				this.accessTokenGenerator.generateKey(), accessTokenClaimsSet.getIssuedAt(), 
                                                                    accessTokenClaimsSet.getExpiresAt(),
				context.getAuthorizedScopes(), accessTokenClaimsSet.getClaims());

		return accessToken;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值