Spring Boot 授权服务器 + Google OAuth2/OpenId Connect 应该使用 access_token 还是 id_token?

问题描述 投票:0回答:1

我对是否应该通过 access_token 还是 id_token 访问我的 Spring Boot 资源服务器有点困惑。

首先,让我快速解释一下我的设置:

  • Spring Boot 应用程序作为 OAuth 2.0 资源服务器。这是按照 Spring 文档中所述进行配置的:JWT 的最小配置此应用程序提供安全的 @Controller,将为 JavaScript SPA(例如 React)提供数据
  • Google 的 OAuth 2.0 AP / OpenID Connect 已配置(凭据、客户端 ID、客户端密钥)
  • 一个 JavaScript SPA 应用程序(例如 React),用于将用户登录到 Google 并向 Spring Boot 资源服务器发出请求以获取安全数据。这些请求包括登录用户的授权标头(带有从 Google 获取的不记名令牌)。
  • 出于开发目的,我还使用 Postman 向 Spring Boot 资源服务器发出请求

我可以轻松配置 Postman 以从 Google 获取令牌。来自 Google 的此令牌响应包括

access_token
id_token
scope
expries_in
token_type
的值。

但是,当 Postman 尝试使用检索到的令牌的

access_token
字段中的值作为授权标头中的 Bearer 时,我对资源服务器的请求被拒绝

我能够成功访问受保护的

@Controllers
的唯一方法是使用
id_token
作为授权标头中的承载者。

我是否应该使用

id_token
作为授权标头中的承载者?或者我应该使用
access_token

一些其他相关信息:

  • id_token
    的值是一个JWT令牌。
    access_token
    的值不是 JWT 令牌。我知道这一点是因为我可以解码
    jwt.io
    上的 id_token,但它无法解码
    access_token
    的值。此外,当我发送
    access_token
    作为 Authorization 标头中的 Bearer 时,Spring Boot 资源服务器失败,并出现以下错误:

尝试解码 Jwt 时发生错误:无效的不安全/JWS/JWE 标头:无效的 JSON:位置 2 处出现意外的令牌 ɭ�。

您不应使用身份令牌来授权对 API 的访问。 要访问 API,您应该使用 OAuth 的访问令牌,该令牌仅适用于受保护的资源 (API),并且内置范围界定。

  • 查看使用 OAuth2 资源服务器的 spring-security-samples,我发现硬编码的
    access_token
    (用于测试目的)的值确实是有效的 JWT。与从 Google 返回的
    access_token
    相反,它不是 JWT。

总结:

  • 我可以使用从 Google 获得的
    id_token
    的值来访问我的 Spring Boot 资源服务器。
    access_token
    的值不是JWT,无法被Spring Boot解析。
  • 是我的理解有问题,我的配置有问题还是什么? Google 的 OpenId Connect 在
    access_token
    的工作方式方面是否有不同的行为?

如果需要,很乐意澄清或添加更多信息。感谢您的考虑和耐心!

spring-boot spring-security google-oauth spring-security-oauth2
1个回答
4
投票

您提到的博客文章在我看来是正确的,并且我相信 OpenID Connect 1.0 规范并不打算将

id_token
用于访问目的。

和您一样,我预计使用 Google 作为授权服务器可以开箱即用,因为 Spring Security 与 Google 一起作为通用 OAuth2 提供者来提供社交登录。然而,事实并非如此,而且我相信这并不是真正的意图,因为 Google 并不是真正的您的授权服务器。例如,我不相信您可以将 Google 配置为使用特定于域的应用程序的范围/权限/权限。这与 Okta 之类的东西不同,Okta 中有很多用于在您自己的租户中配置事物的选项。

我实际上建议查看Spring授权服务器,并将Google配置为联合身份提供商。我目前正在为此制作一个示例,它将在下周左右发布(更新:现在包含在官方示例中)。

话虽如此,如果您仍然对使用 Google 访问令牌对资源服务器进行身份验证的简单用例感兴趣,则需要提供自己的 不透明令牌内省器,它使用 Google 的 tokeninfo 端点。与 Spring Security 期望的不符,所以有点牵扯。

@EnableWebSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .authorizeRequests((authorizeRequests) -> authorizeRequests
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
        // @formatter:on

        return http.build();
    }

    @Bean
    public OpaqueTokenIntrospector introspector() {
        return new GoogleTokenIntrospector("https://oauth2.googleapis.com/tokeninfo");
    }

}
public final class GoogleTokenIntrospector implements OpaqueTokenIntrospector {
    private final RestTemplate restTemplate = new RestTemplate();
    private final String introspectionUri;

    public GoogleTokenIntrospector(String introspectionUri) {
        this.introspectionUri = introspectionUri;
    }

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        RequestEntity<?> requestEntity = buildRequest(token);
        try {
            ResponseEntity<Map<String, Object>> responseEntity = this.restTemplate.exchange(requestEntity, new ParameterizedTypeReference<>() {});
            // TODO: Create and return OAuth2IntrospectionAuthenticatedPrincipal based on response...
        } catch (Exception ex) {
            throw new BadOpaqueTokenException(ex.getMessage(), ex);
        }
    }

    private RequestEntity<?> buildRequest(String token) {
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("access_token", token);

        return new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(introspectionUri));
    }
}
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://accounts.google.com
          jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
© www.soinside.com 2019 - 2024. All rights reserved.