Spring云承载header穿越
Spring cloud bearer header pass through
这似乎是一个很常见的问题,并且有一个简单的答案,但是实施记录的解决方案对我来说不起作用。
我有一个用于所有传入请求的 zuul proxy/gateway,然后将它们转发到不同的微服务。每个传入请求都在 header 中设置了正确的承载令牌(这是在前端设置和验证的(来自 okta)并在跳过 Zuul 并直接进入服务时确认它有效),我只需要通过到微服务上。
EdgeServiceApplication
@EnableHystrix
@EnableZuulProxy
@EnableEurekaClient
@EnableOAuth2Sso
@SpringBootApplication
public class EdgeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EdgeServiceApplication.class, args);
}
}
祖尔application.yml
server:
port: 8080
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
zuul:
sensitiveHeaders: Cookie,Set-Cookie,Authorization
在我的微服务上,
@EnableEurekaClient
@SpringBootApplication
@EnableResourceServer
public class InstanceServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InstanceServiceApplication.class, args);
}
}
当我尝试通过 Zuul 向微服务发送请求时,我收到了 401 响应。
将以下 bean 添加到我的微服务时,我可以看到当请求来自 Zuul 时没有设置授权 header,但是我可以看到它在直接调用时设置了。
@Bean
public FilterRegistrationBean requestDumperFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter requestDumperFilter = new RequestDumperFilter();
registration.setFilter(requestDumperFilter);
registration.addUrlPatterns("/*");
return registration;
}
我是 Spring 的新手所以只是希望我在某处的 .yml 文件中遗漏了一些明显的东西?
当前依赖关系
buildscript {
ext {
springBootVersion = '1.5.8.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath('io.spring.gradle:dependency-management-plugin:0.5.4.RELEASE')
}
}
dependencies {
compile('org.springframework.cloud:spring-cloud-starter-eureka')
compile('org.springframework.cloud:spring-cloud-starter-config')
compile('org.springframework.cloud:spring-cloud-starter-zuul')
compile('org.springframework.cloud:spring-cloud-starter-ribbon')
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-data-rest')
compile("org.springframework.boot:spring-boot-starter-actuator")
compile('org.springframework.boot:spring-boot-starter-websocket')
compile('org.springframework.security.oauth:spring-security-oauth2:2.2.0.RELEASE')
compile('org.springframework.cloud:spring-cloud-security:1.2.1.RELEASE')
}
更新:
按照建议更改我的应用程序后,我仍然会在收到任何请求时遇到 401。
2017-11-02 11:03:05.697 ERROR 7139 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 401 null] with root cause
org.springframework.web.client.HttpClientErrorException: 401 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78) ~[spring-web-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
我开始觉得其他地方出了问题。我有一个 SecurityConfig class 看起来像(我知道生产不安全)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().antMatcher("/**")
.authorizeRequests()
.anyRequest().permitAll();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("*"));
configuration.setAllowedHeaders(ImmutableList.of("*"));
configuration.setAllowCredentials(true);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
我的微服务上唯一的安全配置是
@EnableEurekaClient
@SpringBootApplication
@EnableResourceServer
public class InstanceServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InstanceServiceApplication.class, args);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
@Bean
protected ResourceServerConfigurerAdapter resourceServerConfigurerAdapter() {
return new ResourceServerConfigurerAdapter() {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated();
}
};
}
@Bean
public FilterRegistrationBean requestDumperFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter requestDumperFilter = new RequestDumperFilter();
registration.setFilter(requestDumperFilter);
registration.addUrlPatterns("/*");
return registration;
}
}
更新#2:
注销请求headers,仍然没有授权
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : URI : http://instance-service
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : Method : GET
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : Headers : {Accept=[text/plain, application/json, application/*+json, */*], Content-Length=[0]}
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : Request body:
更新#3:
我制作了一个快速示例应用程序,它还去除了身份验证 headers... https://github.com/peavers/zuul-oauth-passthrough - 希望有人能发现我做错了什么。
The sensitiveHeaders are a blacklist and the default is not empty, so
to make Zuul send all headers (except the "ignored" ones) you would
have to explicitly set it to the empty list. This is necessary if you
want to pass cookie or authorization headers to your back end.
所以 sensitiveHeaders
以相反的方式工作。它们可以防止 header 下游到您的 back-end。与其将 Authorization header 添加到列表中,不如像这样将其从列表中删除:
zuul:
sensitiveHeaders: Cookie,Set-Cookie
或像这样(如果您出于某些原因需要将 Cookie 下游到您的 back-end(我希望您不需要)):
zuul:
sensitiveHeaders:
这似乎是一个很常见的问题,并且有一个简单的答案,但是实施记录的解决方案对我来说不起作用。
我有一个用于所有传入请求的 zuul proxy/gateway,然后将它们转发到不同的微服务。每个传入请求都在 header 中设置了正确的承载令牌(这是在前端设置和验证的(来自 okta)并在跳过 Zuul 并直接进入服务时确认它有效),我只需要通过到微服务上。
EdgeServiceApplication
@EnableHystrix
@EnableZuulProxy
@EnableEurekaClient
@EnableOAuth2Sso
@SpringBootApplication
public class EdgeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EdgeServiceApplication.class, args);
}
}
祖尔application.yml
server:
port: 8080
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
zuul:
sensitiveHeaders: Cookie,Set-Cookie,Authorization
在我的微服务上,
@EnableEurekaClient
@SpringBootApplication
@EnableResourceServer
public class InstanceServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InstanceServiceApplication.class, args);
}
}
当我尝试通过 Zuul 向微服务发送请求时,我收到了 401 响应。
将以下 bean 添加到我的微服务时,我可以看到当请求来自 Zuul 时没有设置授权 header,但是我可以看到它在直接调用时设置了。
@Bean
public FilterRegistrationBean requestDumperFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter requestDumperFilter = new RequestDumperFilter();
registration.setFilter(requestDumperFilter);
registration.addUrlPatterns("/*");
return registration;
}
我是 Spring 的新手所以只是希望我在某处的 .yml 文件中遗漏了一些明显的东西?
当前依赖关系
buildscript {
ext {
springBootVersion = '1.5.8.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath('io.spring.gradle:dependency-management-plugin:0.5.4.RELEASE')
}
}
dependencies {
compile('org.springframework.cloud:spring-cloud-starter-eureka')
compile('org.springframework.cloud:spring-cloud-starter-config')
compile('org.springframework.cloud:spring-cloud-starter-zuul')
compile('org.springframework.cloud:spring-cloud-starter-ribbon')
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-data-rest')
compile("org.springframework.boot:spring-boot-starter-actuator")
compile('org.springframework.boot:spring-boot-starter-websocket')
compile('org.springframework.security.oauth:spring-security-oauth2:2.2.0.RELEASE')
compile('org.springframework.cloud:spring-cloud-security:1.2.1.RELEASE')
}
更新:
按照建议更改我的应用程序后,我仍然会在收到任何请求时遇到 401。
2017-11-02 11:03:05.697 ERROR 7139 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 401 null] with root cause
org.springframework.web.client.HttpClientErrorException: 401 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78) ~[spring-web-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
我开始觉得其他地方出了问题。我有一个 SecurityConfig class 看起来像(我知道生产不安全)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().antMatcher("/**")
.authorizeRequests()
.anyRequest().permitAll();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("*"));
configuration.setAllowedHeaders(ImmutableList.of("*"));
configuration.setAllowCredentials(true);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
我的微服务上唯一的安全配置是
@EnableEurekaClient
@SpringBootApplication
@EnableResourceServer
public class InstanceServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InstanceServiceApplication.class, args);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
@Bean
protected ResourceServerConfigurerAdapter resourceServerConfigurerAdapter() {
return new ResourceServerConfigurerAdapter() {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated();
}
};
}
@Bean
public FilterRegistrationBean requestDumperFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter requestDumperFilter = new RequestDumperFilter();
registration.setFilter(requestDumperFilter);
registration.addUrlPatterns("/*");
return registration;
}
}
更新#2:
注销请求headers,仍然没有授权
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : URI : http://instance-service
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : Method : GET
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : Headers : {Accept=[text/plain, application/json, application/*+json, */*], Content-Length=[0]}
2017-11-02 11:25:24.133 INFO 7381 --- [nio-8080-exec-2] s.s.e.s.c.LoggingRequestInterceptor : Request body:
更新#3:
我制作了一个快速示例应用程序,它还去除了身份验证 headers... https://github.com/peavers/zuul-oauth-passthrough - 希望有人能发现我做错了什么。
The sensitiveHeaders are a blacklist and the default is not empty, so to make Zuul send all headers (except the "ignored" ones) you would have to explicitly set it to the empty list. This is necessary if you want to pass cookie or authorization headers to your back end.
所以 sensitiveHeaders
以相反的方式工作。它们可以防止 header 下游到您的 back-end。与其将 Authorization header 添加到列表中,不如像这样将其从列表中删除:
zuul:
sensitiveHeaders: Cookie,Set-Cookie
或像这样(如果您出于某些原因需要将 Cookie 下游到您的 back-end(我希望您不需要)):
zuul:
sensitiveHeaders: