Spring:转发到 /oauth/token 端点失去身份验证
Spring: forwarding to /oauth/token endpoint loses authentication
我正在构建一个 Spring 启动授权服务器,它需要使用两种不同的身份验证方法生成 Oauth2 令牌。我希望每个方法都有不同的端点,但默认情况下 Spring 只创建 /oauth/token
,虽然它可以更改,但我认为不可能有两个不同的路径。
作为替代方案,我试图在控制器中创建两个方法,它们执行内部 forward 到 /oauth/token
,向请求添加一个参数,所以我可以知道它是从哪里来的。
我有这样的东西:
@RequestMapping(value = "/foo/oauth/token", method = RequestMethod.POST)
public ModelAndView fooOauth(ModelMap model) {
model.addAttribute("method", "foo");
return new ModelAndView("forward:/oauth/token", model);
}
这正确执行了转发,但身份验证失败:
There is no client authentication. Try adding an appropriate authentication filter.
同样的请求直接发送到/oauth/token
时可以正常工作,所以我猜测问题是转发后的BasicAuthenticationFilter不是运行。
我怎样才能让它发挥作用?
仔细查看为 Oauth 端点和转发控制器创建的过滤器链,很容易看出后者缺少 BasicAuthenticationFilter,因为它们未经过身份验证,并且在之后不会再次执行身份验证前锋。
为了解决这个问题,我创建了一个这样的新配置:
@Configuration
public class ForwarderSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();
@Autowired
private FooClientDetailsService fooClientDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
AuthorizationServerSecurityConfigurer configurer = new AuthorizationServerSecurityConfigurer();
for (AuthorizationServerConfigurer configurerBit : configurers) configurerBit.configure(configurer);
http.apply(configurer);
http
.authorizeRequests()
.antMatchers("/foo/oauth/token").fullyAuthenticated()
.and()
.requestMatchers()
.antMatchers("/foo/oauth/token");
http.setSharedObject(ClientDetailsService.class, fooClientDetailsService);
}
}
此代码模仿 Spring Oauth 在幕后所做的工作 (here),运行在两个端点上使用相同的身份验证选项设置相同的过滤器链。
当 /oauth/token
端点最终 运行 时,它找到了它期望的身份验证结果,并且一切正常。
最后,如果您想 运行 在两个转发端点上使用不同的 ClientDetailsService,您只需创建两个像这样的配置 classes,并替换 [=12] 上的 ClientDetailsService =] 召集他们每个人。请注意,为此,您必须在每个 class.
中设置不同的 @Order
值
我遇到了完全相同的问题。经过一些研究,我发现问题是由 Spring Boot 2 而不是 Spring 安全配置引起的。根据 Spring Boot 2.0 migration guide:
Spring Security and Spring Session filters are configured for ASYNC, ERROR, and REQUEST dispatcher types.
和 Spring Boot 的 SecurityFilterAutoConfiguration 源代码:
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
private EnumSet<DispatcherType> getDispatcherTypes(
SecurityProperties securityProperties) {
if (securityProperties.getFilter().getDispatcherTypes() == null) {
return null;
}
return securityProperties.getFilter().getDispatcherTypes().stream()
.map((type) -> DispatcherType.valueOf(type.name())).collect(Collectors
.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
}
其中 securityProperties.getFilter().getDispatcherTypes()
的默认值在 SecurityProperties 中定义为:
private Set<DispatcherType> dispatcherTypes = new HashSet<>(
Arrays.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
因此,默认情况下,Spring Boot 配置 Spring 安全性,以便其过滤器不会应用于 FORWARD 请求(但仅适用于 ASYNC、ERROR 和 REQUEST),因此没有安全过滤器会在将请求转发到 /oauth/token
.
时应用于对请求进行身份验证
解决方法很简单。您可以将以下行添加到 application.properties
以便将默认过滤器应用于所有转发的请求
spring.security.filter.dispatcher-types=async,error,request,forward
或者使用路径匹配器和 dispatcherType=FORWARD 创建您自己的自定义过滤器链,以仅过滤转发到 /oauth/token
.
的请求
我正在构建一个 Spring 启动授权服务器,它需要使用两种不同的身份验证方法生成 Oauth2 令牌。我希望每个方法都有不同的端点,但默认情况下 Spring 只创建 /oauth/token
,虽然它可以更改,但我认为不可能有两个不同的路径。
作为替代方案,我试图在控制器中创建两个方法,它们执行内部 forward 到 /oauth/token
,向请求添加一个参数,所以我可以知道它是从哪里来的。
我有这样的东西:
@RequestMapping(value = "/foo/oauth/token", method = RequestMethod.POST)
public ModelAndView fooOauth(ModelMap model) {
model.addAttribute("method", "foo");
return new ModelAndView("forward:/oauth/token", model);
}
这正确执行了转发,但身份验证失败:
There is no client authentication. Try adding an appropriate authentication filter.
同样的请求直接发送到/oauth/token
时可以正常工作,所以我猜测问题是转发后的BasicAuthenticationFilter不是运行。
我怎样才能让它发挥作用?
仔细查看为 Oauth 端点和转发控制器创建的过滤器链,很容易看出后者缺少 BasicAuthenticationFilter,因为它们未经过身份验证,并且在之后不会再次执行身份验证前锋。
为了解决这个问题,我创建了一个这样的新配置:
@Configuration
public class ForwarderSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();
@Autowired
private FooClientDetailsService fooClientDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
AuthorizationServerSecurityConfigurer configurer = new AuthorizationServerSecurityConfigurer();
for (AuthorizationServerConfigurer configurerBit : configurers) configurerBit.configure(configurer);
http.apply(configurer);
http
.authorizeRequests()
.antMatchers("/foo/oauth/token").fullyAuthenticated()
.and()
.requestMatchers()
.antMatchers("/foo/oauth/token");
http.setSharedObject(ClientDetailsService.class, fooClientDetailsService);
}
}
此代码模仿 Spring Oauth 在幕后所做的工作 (here),运行在两个端点上使用相同的身份验证选项设置相同的过滤器链。
当 /oauth/token
端点最终 运行 时,它找到了它期望的身份验证结果,并且一切正常。
最后,如果您想 运行 在两个转发端点上使用不同的 ClientDetailsService,您只需创建两个像这样的配置 classes,并替换 [=12] 上的 ClientDetailsService =] 召集他们每个人。请注意,为此,您必须在每个 class.
中设置不同的@Order
值
我遇到了完全相同的问题。经过一些研究,我发现问题是由 Spring Boot 2 而不是 Spring 安全配置引起的。根据 Spring Boot 2.0 migration guide:
Spring Security and Spring Session filters are configured for ASYNC, ERROR, and REQUEST dispatcher types.
和 Spring Boot 的 SecurityFilterAutoConfiguration 源代码:
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
private EnumSet<DispatcherType> getDispatcherTypes(
SecurityProperties securityProperties) {
if (securityProperties.getFilter().getDispatcherTypes() == null) {
return null;
}
return securityProperties.getFilter().getDispatcherTypes().stream()
.map((type) -> DispatcherType.valueOf(type.name())).collect(Collectors
.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
}
其中 securityProperties.getFilter().getDispatcherTypes()
的默认值在 SecurityProperties 中定义为:
private Set<DispatcherType> dispatcherTypes = new HashSet<>(
Arrays.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
因此,默认情况下,Spring Boot 配置 Spring 安全性,以便其过滤器不会应用于 FORWARD 请求(但仅适用于 ASYNC、ERROR 和 REQUEST),因此没有安全过滤器会在将请求转发到 /oauth/token
.
解决方法很简单。您可以将以下行添加到 application.properties
以便将默认过滤器应用于所有转发的请求
spring.security.filter.dispatcher-types=async,error,request,forward
或者使用路径匹配器和 dispatcherType=FORWARD 创建您自己的自定义过滤器链,以仅过滤转发到 /oauth/token
.