Spring:转发到/ oauth / token端点会丢失身份验证

问题描述 投票:2回答:2

我正在构建一个Spring Boot授权服务器,该服务器需要使用两种不同的auth方法来生成Oauth2令牌。我希望每种方法都有一个不同的端点,但是默认情况下,Spring仅创建/oauth/token,尽管可以更改,但我认为不可能有两个不同的路径。

作为替代,我试图在控制器中创建两个对/oauth/token进行内部forward的方法,向请求中添加参数,以便可以知道它的来源。

我有这样的东西:

@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没有运行。

如何使它起作用?

spring-boot spring-security spring-oauth2
2个回答
2
投票

我有完全相同的问题。经过研究,我发现问题是由Spring Boot 2引起的,而不是由Spring Security配置引起的。根据Spring Boot 2.0 migration guide

Spring Security和Spring Session过滤器配置为ASYNC,ERROR和REQUEST调度程序类型。

和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 Security,以便其过滤器不会应用于FORWARD请求(而仅应用于ASYNC,ERROR和REQUEST),因此,在将请求转发至[时,不会应用安全过滤器对请求进行身份验证C0]。

解决方案很简单。您可以将以下行添加到/oauth/token,以便将默认过滤器应用于所有转发的请求

application.properties

或使用路径匹配器和dispatcherType = FORWARD创建您自己的自定义过滤器链,以仅过滤要发送到spring.security.filter.dispatcher-types=async,error,request,forward 的请求。


-1
投票

仔细查看为Oauth端点和转发控制器创建的过滤器链,很容易看到后者缺少BasicAuthenticationFilter,因为它们没有经过身份验证,并且转发后不再执行auth。

为了解决这个问题,我创建了一个新的配置,如下所示:

/oauth/token

此代码模仿了Spring Oauth在后台(@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); } } )所做的工作,在两个端点上使用相同的身份验证选项运行相同的筛选器链。

here端点最终运行时,它将找到期望的身份验证结果,并且一切正常。

最后,如果要在两个转发终结点上运行不同的ClientDetailsS​​ervice,只需创建两个这样的配置类,然后在每个/oauth/token调用上替换ClientDetailsS​​ervice。请注意,为此,您必须在每个类中设置不同的setSharedObject值。

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