CORS не работает в Spring 4.3 с OAuth2

Вот что я получаю в консоли Chrome при отправке запроса с помощью приложения Angular 1.5:

XMLHttpRequest не может загрузить http://localhost:8080/api/oauth/token. Ответ на предварительный запрос не проходит проверку управления доступом: в запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin». Таким образом, доступ к источнику 'http://localhost:8000' запрещен. В ответе был код состояния HTTP 401.

Когда я удаляю конфигурацию OAuth2, ошибка исчезает.

Это моя конфигурация CORS:

class AppWebSpringConfig extends WebMvcConfigurerAdapter implements ServletContextAware {

...

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("X-Requested-With", "X-Auth-Token", "Origin", "Content-Type", "Accept")
                .allowCredentials(false)
                .maxAge(3600);
    }

...
}

И мои классы конфигурации OAuth2:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new OAuth2MethodSecurityExpressionHandler();
    }

}

@Configuration
class OAuth2ServerConfiguration {

    private static final int ONE_HOUR = 3600;
    private static final int THIRTY_DAYS = 2592000;

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                    .authorizeRequests()
                    .anyRequest().authenticated();
            // @formatter:on
        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Autowired
        private UserSecurityService userSecurityService;

        @Autowired
        private DataSource dataSource;

        @Autowired
        private Environment env;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // @formatter:off
            endpoints
                    .tokenStore(tokenStore())
                    .authenticationManager(authenticationManager)
                    .userDetailsService(userSecurityService);
            // @formatter:on
        }

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off
            clients
                    .jdbc(dataSource)
                    .withClient(env.getProperty(CLIENT_ID_WEB))
                    .secret(env.getProperty(CLIENT_SECRET_WEB))
                    .authorizedGrantTypes("password", "refresh_token")
                    .scopes("read", "write")
                    .accessTokenValiditySeconds(ONE_HOUR)
                    .refreshTokenValiditySeconds(THIRTY_DAYS);
            // @formatter:on
        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            final DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(tokenStore());
            return tokenServices;
        }

    }

}

РЕДАКТИРОВАТЬ: я также пробовал использовать следующую реализацию фильтра, но это не работает. Ставлю точку останова в методе doFilter(), но выполнение на этом не останавливается, как будто мой фильтр не зарегистрирован. Однако, когда я добавил в фильтр дефолтный конструктор и поставил там точку останова — он остановился, а значит, фильтр прописан.

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {

    public SimpleCorsFilter() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}

Я также пытался использовать этот подход, но снова не повезло: Разрешить OPTIONS HTTP Метод запроса oauth/токена

Я думаю, что конфигурация OAuth2 не позволяет запросу даже пройти через настроенный фильтр CORS. Кто-нибудь знает решение этой проблемы?

EDIT2: Итак, оказывается, что был класс:

public class AppSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

    // nothing here, using defaults

}

Как только я прокомментировал это, конфигурация CORS начала работать (вероятно, из-за прохождения фильтров), НО теперь моя конфигурация OAuth2 вообще не работает! Каждый URL-адрес выставлен без защиты. есть идеи?


person pegasus    schedule 28.08.2016    source источник


Ответы (1)


Привет, у меня была такая же проблема с spring 4.3, но вот ответ: -

Вам необходимо переопределить следующий метод AuthorizationServerConfigurerAdapter в вашем классе AuthorizationServerConfiguration и добавить туда фильтр CORS, используя метод addTokenEndpointAuthenticationFilter AuthorizationServerSecurityConfigurer, как показано ниже:

 @Override
 public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
       security.addTokenEndpointAuthenticationFilter(new CORSFilter());
 }

Ваш класс AuthorizationServerConfiguration будет: -

 @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Autowired
        private UserSecurityService userSecurityService;

        @Autowired
        private DataSource dataSource;

        @Autowired
        private Environment env;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // @formatter:off
            endpoints
                    .tokenStore(tokenStore())
                    .authenticationManager(authenticationManager)
                    .userDetailsService(userSecurityService);
            // @formatter:on
        }

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off
            clients
                    .jdbc(dataSource)
                    .withClient(env.getProperty(CLIENT_ID_WEB))
                    .secret(env.getProperty(CLIENT_SECRET_WEB))
                    .authorizedGrantTypes("password", "refresh_token")
                    .scopes("read", "write")
                    .accessTokenValiditySeconds(ONE_HOUR)
                    .refreshTokenValiditySeconds(THIRTY_DAYS);
            // @formatter:on
        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            final DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(tokenStore());
            return tokenServices;
        }

        // ***** Here I added CORS filter *****
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
              security.addTokenEndpointAuthenticationFilter(new CORSFilter());
        }  
}
person Koustubh Mokashi    schedule 08.12.2016