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

时间:2018-06-08 11:09:01

标签: spring-boot spring-security spring-oauth2

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

作为替代方案,我正在尝试在控制器中创建两个方法,这些方法执行内部转发/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);
}

这正确地执行了转发,但是auth失败了:

There is no client authentication. Try adding an appropriate authentication filter.

直接发送到/oauth/token时,相同的请求正常工作,所以我猜测问题是BasicAuthenticationFilter在转发后没有运行。

我怎样才能让它发挥作用?

2 个答案:

答案 0 :(得分:1)

我有完全一样的问题。经过研究后,我发现问题是由 Spring Boot 2 引起的,而不是由Spring Security配置引起的。根据{{​​3}}:

  

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

和Spring Boot的Spring Boot 2.0 migration guide源代码:

@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));

}

默认情况下,Spring Boot配置Spring Security,以使其过滤器不会应用于FORWARD请求(仅ASYNC,ERROR和REQUEST),因此在将请求转发到/oauth/token之前,不会应用过滤器对请求进行身份验证

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

spring.security.filter.dispatcher-types=async,error,request,forward

或使用路径匹配器和dispatcherType = FORWARD创建您自己的自定义过滤器链,以仅过滤要发送到/oauth/token的请求。

答案 1 :(得分:-1)

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

为了解决这个问题,我创建了一个像这样的新配置:

@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端点最终运行时,它会找到它所期望的auth结果,一切正常。

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