Spring security Faign和Spring Security 5-客户端凭据
我试图调用某个后端系统,该系统由来自外部客户端应用程序的客户端\ U凭据授予类型保护 可以使用以下curl结构从后端系统检索访问令牌(仅作为示例): 然后,应在对后端系统的后续业务调用的头中设置此accessToken 所以现在我的问题是,如何使用Feign和springbootsecurity5实现这一点。 经过一些研究,我得出了这个解决方案(不起作用):Spring security Faign和Spring Security 5-客户端凭据,spring-security,oauth,spring-cloud-feign,Spring Security,Oauth,Spring Cloud Feign,我试图调用某个后端系统,该系统由来自外部客户端应用程序的客户端\ U凭据授予类型保护 可以使用以下curl结构从后端系统检索访问令牌(仅作为示例): 然后,应在对后端系统的后续业务调用的头中设置此accessToken 所以现在我的问题是,如何使用Feign和springbootsecurity5实现这一点。 经过一些研究,我得出了这个解决方案(不起作用): 在application.yml中定义我的客户端: 创建OAuth2AuthorizedClientManager Bean,以便能够授权
@Bean
公共OAuth2AuthorizedClientManager授权dClientManager(
ClientRegistrationRepository ClientRegistrationRepository,
OAuth2AuthorizedClientPosition授权客户(授权客户){
DefaultOAuth2AuthorizedClientManager授权dClientManager=
新的DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository,授权客户库);
返回授权客户管理器;
}
公共类OAuthRequestInterceptor实现RequestInterceptor{
专用OAuth2AuthorizedClient管理器;
公共OAuthRequestInterceptor(OAuth2AuthorizedClient管理器){
this.manager=经理;
}
@凌驾
公共作废应用(RequestTemplate RequestTemplate){
OAuth2AuthorizedClient=this.manager.authorize(OAuth2AuthorizeRequest.withClientRegistrationId(“后端”).principal(createPrincipal()).build());
字符串accessToken=client.getAccessToken().getTokenValue();
requestTemplate.header(HttpHeaders.AUTHORIZATION,“Bearer”+accessToken);
}
私有身份验证createPrincipal(){
返回新的身份验证(){
@凌驾
公共收藏我尝试了you's方法。不幸的是没有成功。但这一个对我有效:。看起来我现在使用了很多折旧,但至少它确实有效。我对Faign和OAuth2很有经验,我花了好几个小时才找到如何做到这一点。
首先,假设我的应用程序基于最新的Spring库,因此我使用以下依赖项(Spring cloud starter openfeign的托管版本为3.0.0)
最后是我的配置bean
package es.spanishkangaroo.ttanalyzer.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.openfeign.security.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import feign.RequestInterceptor;
@Configuration
public class FeignClientConfiguration {
@Bean
@ConfigurationProperties(prefix = "security.oauth2.client")
public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
return new ClientCredentialsResourceDetails();
}
@Bean
public RequestInterceptor oauth2FeignRequestInterceptor(){
return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());
}
@Bean
public OAuth2RestTemplate clientCredentialsRestTemplate() {
return new OAuth2RestTemplate(clientCredentialsResourceDetails());
}
}
因此,外国客户机就像
package es.spanishkangaroo.ttanalyzer.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import es.clovelly.ttanalyzer.model.Trends;
@FeignClient(name = "twitterClient", url = "https://api.twitter.com/1.1/")
public interface TwitterClient {
@GetMapping("/trends/place.json")
Trends[] getTrendsById(@RequestParam Long id);
}
正如您可能已经注意到的,代码在客户端调用之前自动获取令牌(承载令牌)
@Bean
public OAuth2ClientContext oAuth2ClientContext() {
DefaultOAuth2ClientContext context = new DefaultOAuth2ClientContext();
context.setAccessToken(bearerToken);
return context;
}
要使它与SpringSecurity5一起工作,您需要
- 工作的Spring安全配置
- 假拦截器
- 使用该拦截器的虚假配置
工作弹簧安全配置
在这里,我们将为您的oauth2客户端凭据注册一个通用的内部api
客户端。在这里,您可以指定客户端机密
、客户端机密
、作用域
和授权类型
。
所有基本的Spring Security 5功能。这还包括设置一个提供程序(这里我使用一个名为“yourprovider”的自定义OpenID连接提供程序)
接下来,您需要您的伪配置。这将使用一个OAuth2FeignRequestInterceptor
public class ServiceToServiceFeignConfiguration extends AbstractFeignConfiguration {
@Bean
public OAuth2FeignRequestInterceptor requestInterceptor() {
return new OAuth2FeignRequestInterceptor(
OAuth2AuthorizeRequest.withClientRegistrationId("internal-api")
.principal(new AnonymousAuthenticationToken("feignClient", "feignClient", createAuthorityList("ROLE_ANONYMOUS")))
.build());
}
}
还有一个请求拦截器,如下所示:
OAuth2AuthorizedClient Manager是一个可以在配置中配置的bean
public OAuth2AuthorizedClientManager authorizedClientManager(final ClientRegistrationRepository clientRegistrationRepository, final OAuth2AuthorizedClientService authorizedClientService) {
return new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
}
OAuth2AuthorizerRequest
由上面的外部配置提供。
OAuth2AuthorizedClient Manager
可以授权oAuth2AuthorizeRequest
,获取访问令牌,并将其作为授权头提供给基础服务
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
@Inject
private OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager;
private OAuth2AuthorizeRequest oAuth2AuthorizeRequest;
OAuth2FeignRequestInterceptor(OAuth2AuthorizeRequest oAuth2AuthorizeRequest) {
this.oAuth2AuthorizeRequest = oAuth2AuthorizeRequest;
}
@Override
public void apply(RequestTemplate template) {
template.header(AUTHORIZATION,getAuthorizationToken());
}
private String getAuthorizationToken() {
final OAuth2AccessToken accessToken = oAuth2AuthorizedClientManager.authorize(oAuth2AuthorizeRequest).getAccessToken();
return String.format("%s %s", accessToken.getTokenType().getValue(), accessToken.getTokenValue());
}
}
在切换到Spring Security 5之前,我们使用了Spring Security OAuth2包中的ClientCredentialAccessTokenProvider
。这很有效。感谢您的回答。这当然有效,但它是Spring Security OAuth2的一部分,而Spring Security 5.x已经被弃用了。我真的想让它在Spring Security中发挥作用5.x.ClientCredentialsResourceDetails
不是被弃用了吗?读了这篇文章,我倾向于这样想:我们怎么能检查呢?谢谢你的详细回答。但是,我没有得到一些东西:什么是classAbstractFeignConfiguration
+methodwith clientRegistrationId()
[它是OAuth2AuthorizerRequest.withClientRegistrationId()
?];在OAuth2FeignRequestInterceptor
中也是一样的,authorizationHeader()
来自哪里?谢谢。更改代码后,它确实是OAuth2AuthorizerRequest.withClientRegistrationId
(使用静态导入)这里,authorizationHeader
是一个UTILITY方法。为了clarityOK很好,现在删除了它……并且从AbstractFeignConfiguration
继承的没有什么特别的东西?或者它是注释的吗?在我们的例子中,AbstractFeignConfiguration只包含一些解码器/编码器。这里不需要
package es.spanishkangaroo.ttanalyzer.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import es.clovelly.ttanalyzer.model.Trends;
@FeignClient(name = "twitterClient", url = "https://api.twitter.com/1.1/")
public interface TwitterClient {
@GetMapping("/trends/place.json")
Trends[] getTrendsById(@RequestParam Long id);
}
@Bean
public OAuth2ClientContext oAuth2ClientContext() {
DefaultOAuth2ClientContext context = new DefaultOAuth2ClientContext();
context.setAccessToken(bearerToken);
return context;
}
spring:
security:
oauth2:
client:
registration:
internal-api:
provider: yourprovider
client-id: x
client-secret: y
scope:
- ROLE_ADMIN
authorization-grant-type: client_credentials
provider:
yourprovider:
issuer-uri: yourprovider.issuer-uri
resourceserver:
jwt:
issuer-uri: yourprovider.issuer-uri
public class ServiceToServiceFeignConfiguration extends AbstractFeignConfiguration {
@Bean
public OAuth2FeignRequestInterceptor requestInterceptor() {
return new OAuth2FeignRequestInterceptor(
OAuth2AuthorizeRequest.withClientRegistrationId("internal-api")
.principal(new AnonymousAuthenticationToken("feignClient", "feignClient", createAuthorityList("ROLE_ANONYMOUS")))
.build());
}
}
public OAuth2AuthorizedClientManager authorizedClientManager(final ClientRegistrationRepository clientRegistrationRepository, final OAuth2AuthorizedClientService authorizedClientService) {
return new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
}
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
@Inject
private OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager;
private OAuth2AuthorizeRequest oAuth2AuthorizeRequest;
OAuth2FeignRequestInterceptor(OAuth2AuthorizeRequest oAuth2AuthorizeRequest) {
this.oAuth2AuthorizeRequest = oAuth2AuthorizeRequest;
}
@Override
public void apply(RequestTemplate template) {
template.header(AUTHORIZATION,getAuthorizationToken());
}
private String getAuthorizationToken() {
final OAuth2AccessToken accessToken = oAuth2AuthorizedClientManager.authorize(oAuth2AuthorizeRequest).getAccessToken();
return String.format("%s %s", accessToken.getTokenType().getValue(), accessToken.getTokenValue());
}
}