使用Oauth2通过Spring Boot调用Auth0 API

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

我有一个 Spring Boot 3 服务,它使用 Auth0/Okta 来保护其 API。用户获得令牌并可以调用我的端点。我在 application.yaml 中使用这些参数:

okta:
  oauth2:
    audience: 
    issuer: 

我的服务还需要能够调用 Auth0,例如能够使用 OAuth2 令牌创建用户

Auth0 端的设置已正确,因为在使用为我的服务颁发的 clientId 和 clientSecret 检索令牌后,我可以使用 Postman 进行调用。

我认为使用 SDK 和启动器并将其嵌入到我的服务中会很简单,但我没有找到实现这一目标的方法:

并通过私钥:

我找不到任何关于如何使用 Oauth2 实现类似目标的资源。

当我“手动”尝试时,通过自己设置更多代码,我无法获得令牌,因为 Auth0 需要一个

audience
参数,而 Spring Security 不支持开箱即用的参数(https:// github.com/spring-projects/spring-security/issues/6569

考虑到 Spring Boot 和 Auth0 的流行,我本以为这会很容易,但事实证明,我没有找到任何一个可以在 Spring Boot 3 / Spring Security 6 中或多或少开箱即用的示例..

最后,这些都是有用的资源:

我是否错过了文档中的任何内容,或者真的没有更好的方法使用 OAuth2 调用 Auth0 API 吗?

spring-boot spring-security auth0 okta
1个回答
0
投票

我刚刚完成了这个练习,所以请允许我提供帮助。

首先,我要说的是,我使用了okta SDK和Auth0.com,但没有得到很好的体验。

<dependency>
    <groupId>com.okta</groupId>
    <artifactId>okta-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
  1. 它工作得不好,因为它与 Spring 框架没有很好地集成。
  2. 为什么不使用 openID-Connect 和 OAuth2 标准,因为它们与 openid-connect 和 oauth2 更兼容。

我还使用了 Okta 的 Auth0,因为它是一个免费的面向开发人员的平台。

我的项目使用了Spring安全依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

我的项目还做了用于登录的常规 Web 应用程序和用于 API 的资源服务器。由于您只对资源服务器感兴趣,我可以向您展示这一点。

将其添加到您的 application.yml 中。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: ${auth0audience-issuer-uri}
          audiences: ${auth0audience-audience}
      client:
        registration:
          auth0:
            client-id: ${auth0audience-client-id}
            client-secret: ${auth0audience-client-secret}
            provider: auth0
        provider:
          auth0:
            issuer-uri: ${auth0audience-issuer-uri}

然后配置

SecurityFilterChain

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())).build();
    }
}

正如您所发现的,困难实际上在于通过 WebClient 访问它。必须配置添加

audience
参数

@Configuration
public class WebClientConfiguration {
    @Value("${spring.security.oauth2.resourceserver.jwt.audiences}")
    private String audience;

    @Bean
    public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
                new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);

        return WebClient.builder()
                .apply(oauth2Client.oauth2Configuration())
                .baseUrl("http://localhost:8080/")
                .build();
    }

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientService authorizedClientService) {

        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials((builder) ->
                                builder.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient())
                                        .build())
                        .build();

        AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
                new AuthorizedClientServiceOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientService);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }

    private OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
        DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
                new DefaultClientCredentialsTokenResponseClient();

        OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter =
                new OAuth2ClientCredentialsGrantRequestEntityConverter();
        requestEntityConverter.addParametersConverter(source -> CollectionUtils.toMultiValueMap(Collections.singletonMap("audience", Collections.singletonList(audience))));
        accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);

        return accessTokenResponseClient;
    }

}

然后就可以使用了。

@SpringBootApplication
public class Auth0WebClientAudienceApplication implements ApplicationRunner {

    public static void main(String[] args) {
        SpringApplication.run(Auth0WebClientAudienceApplication.class, args);
    }

    @Autowired
    WebClient webClient;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<String> r = webClient.get().uri("movies")
                .attributes(clientRegistrationId("auth0"))
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<List<String>>() {
                }).block();
        System.out.println("movies = " + r);
    }
}

仅供参考

@RestController
@RequestMapping
public class MovieApi {
    @GetMapping("movies")
    public List<String> getMovies() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        if (!(securityContext instanceof AnonymousAuthenticationToken)) {
            return List.of("movie1", "movie2");
        }
        return Collections.emptyList();
    }
}

Git 存储库位于 Auth0WebClientAudience

Spring Security Framework 在 OAuth 2.0 Client 上有一些不充分的文档。

© www.soinside.com 2019 - 2024. All rights reserved.