簡體   English   中英

Spring 在 Feign 上沒有 web 環境的情況下啟動 OAuth2

[英]Spring Boot OAuth2 without web environment on Feign

我正在使用 Spring Boot 2.3.4,我需要調用需要 oauth2 身份驗證的外部 web 服務。

目前我已經通過這種方式使用 feign 實現了這一點

客戶

@FeignClient(name = "myClient", value = "myClient", url = "${app.my.client.apiUrl}", configuration = MyClientConfiguration.class)
    public interface MyClient {
    
    @GetMapping(value = "/api/my-url", consumes = "application/json")
    String getSomeData();
}

客戶端配置

public class MyClientConfiguration {
    private final OAuth2AuthorizedClientService oAuth2AuthorizedClientService;
    private final ClientRegistrationRepository clientRegistrationRepository;

        public MyClientConfiguration(OAuth2AuthorizedClientService oAuth2AuthorizedClientService, ClientRegistrationRepository clientRegistrationRepository) {
            this.oAuth2AuthorizedClientService = oAuth2AuthorizedClientService;
            this.clientRegistrationRepository = clientRegistrationRepository;
        }
    
        @Bean
        public RequestInterceptor requestInterceptor() {
            ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId("my-client");
            AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, oAuth2AuthorizedClientService);
            authorizedClientManager.setAuthorizedClientProvider(OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build());
            return new OAuthClientCredentialsRestTemplateInterceptor(authorizedClientManager, clientRegistration);
        }
    }

OAuth攔截器

public class OAuthClientCredentialsRestTemplateInterceptor implements RequestInterceptor {
        private static final String BEARER_HEADER_NAME = "Bearer";
        private final OAuth2AuthorizedClientManager manager;
        private final Authentication emptyPrincipal;
        private final ClientRegistration clientRegistration;
    
        public OAuthClientCredentialsRestTemplateInterceptor(OAuth2AuthorizedClientManager manager, ClientRegistration clientRegistration) {
            this.manager = manager;
            this.clientRegistration = clientRegistration;
            this.emptyPrincipal = createEmptyPrincipal();
        }
    
        @Override
        public void apply(RequestTemplate requestTemplate) {
            OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistration.getRegistrationId()).principal(emptyPrincipal).build();
            OAuth2AuthorizedClient client = manager.authorize(oAuth2AuthorizeRequest);
            if (client == null)
                throw new IllegalStateException("Cannot retrieve a valid client for registration " + clientRegistration.getRegistrationId());
            requestTemplate.header(HttpHeaders.AUTHORIZATION, BEARER_HEADER_NAME + " " + client.getAccessToken().getTokenValue());
        }
    
        private Authentication createEmptyPrincipal() {
            return new Authentication() {
                @Override
                public Collection<? extends GrantedAuthority> getAuthorities() {
                    return Collections.emptySet();
                }
    
                @Override
                public Object getCredentials() {
                    return null;
                }
    
                @Override
                public Object getDetails() {
                    return null;
                }
    
                @Override
                public Object getPrincipal() {
                    return this;
                }
    
                @Override
                public boolean isAuthenticated() {
                    return false;
                }
    
                @Override
                public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
                }
    
                @Override
                public String getName() {
                    return clientRegistration.getClientId();
                }
            };
        }
    }

特性

spring:
  security:
    oauth2:
      client:
        registration:
          microsoft:
            client-id: ******
            client-secret:  ******
            scope:  ******
            authorization-grant-type: client_credentials
            provider: my-client
        provider:
          my-client:
            token-uri: ******

app:
  my-client:
    apiUrl: https://my-url.com

feign:
  hystrix:
    enabled: false
  client:
    config:
      default:
        connect-timeout: 3000

在另一個項目中,我需要相同的但它是一個沒有 web 環境的 spring 啟動應用程序,並且出現以下錯誤

bean of type 'org.springframework.security.oauth2.client.OAuth2AuthorizedClientService' that could not be found.

我該如何解決這種情況?

是否可以在沒有 tomcat(或類似)的環境中使用 oauth2 自動配置?

您需要配置一個單獨的類並告訴 spring IOC 這是無狀態會話。

@Configuration
@EnableWebSecurity
public class SecurityConfigForOauth extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().httpBasic().disable().formLogin().disable().logout().disable().sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

}

檢查我關於如何讓 client_credentials 在https://stackoverflow.com/a/65741386/698471 上工作的回復,對 spring-boot-starter-web 沒有直接依賴

不是解決方案,只是將微服務轉換為微應用程序的解決方法:通過不使用批處理屬性或設置spring.batch.job.enabled=true然后終止進程,讓作業在應用程序啟動期間的配置時間運行。

@SpringBootApplication
public class MyBootApp implements CommandLineRunner {

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

//Runs after @Configuration classes are finished synchronously including batch jobs.
@Override
public void run(String... args) throws Exception {
    System.exit(0); 
}

}

似乎 RestTemplate 和 WebClient 正在使用 spring-web 配置文件來自動裝配 OAuth 攔截器所需的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM