首页 文章

Spring安全4.2.3,OAUTH 2,/ oauth / token endpoints ,CORS不能正常工作

提问于
浏览
0

Angular 5 app需要登录用户 . 令牌请求被发送到/ oauth / token . 由于CORS,预检OPTIONS请求(由Chrome发送)失败 .

我尝试按照Spring Security 4.2上的示例和Stackoverflow上的各种问题和响应进行操作 .

这是我的代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
        .cors().and()
        .csrf().disable()
            .anonymous().disable()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
        .antMatchers("/signup").permitAll()
        .antMatchers("/oauth/token").permitAll()
        .antMatchers("/fapi/**").authenticated()
        .and()
        .httpBasic()
            .realmName("MY_REALM");
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://example.com"));
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"));
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    ............
}

以下是Chrome的请求

General Headers

Request URL: http://api.example.com/oauth/token
Request Method: OPTIONS
Status Code: 401 
Remote Address: 127.65.43.21:80
Referrer Policy: no-referrer-when-downgrade


Request headers

Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: POST
Cache-Control: no-cache
Connection: keep-alive
Host: api.example.com
Origin: http://example.com
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36

响应:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Language: en
Content-Length: 1111
Content-Type: text/html;charset=utf-8
Date: Mon, 07 May 2018 03:23:15 GMT
Expires: 0
Pragma: no-cache
WWW-Authenticate: Basic realm="MY_REALM"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

和控制台中的错误:

Failed to load http://api.example.com/oauth/token: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access. The response had HTTP status code 401.

2 回答

  • -1

    我无法使用Spring提供的CorsFilter .

    这里的工作有所帮助 .

    Spring security, cors error when enable Oauth2

    最终代码的一部分

    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    @WebFilter("/*")
    public class SimpleCORSFilter implements Filter {
    
        public SimpleCORSFilter() {
        }
    
        @Override
        public void init(FilterConfig fc) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse resp,
                             FilterChain chain) throws IOException, ServletException {
    
            System.out.println("doFilter");
            HttpServletResponse response = (HttpServletResponse) resp;
            HttpServletRequest request = (HttpServletRequest) req;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "Origin, origin, x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
    
            if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
                response.setStatus(HttpServletResponse.SC_OK);
            } else {
                chain.doFilter(req, resp);
            }    
        }
    
        @Override
        public void destroy() {
        }    
    }
    

    在安全配置中:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers(HttpMethod.OPTIONS, "/oauth/token");
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http
          //.cors().and()
            .csrf().disable()
                .anonymous().disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/signup").permitAll()
            .antMatchers("/oauth/token").permitAll()
            .antMatchers("/fapi/**").authenticated()
            .and()
            .httpBasic()
                .realmName("MY_REALM");
        }
    
        /*
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(Arrays.asList("http://example.com"));
            configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"));
            configuration.addAllowedHeader("*");
            configuration.setAllowCredentials(true);
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
            return source;
        }*/
        ............
    }
    

    我还在等待一个让它与Spring Security的CorsFilter一起工作的例子 .

  • 0

    而不是你做了什么,写一个自定义的cors过滤器,如下所示

    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class SimpleCorsFilter implements Filter {
    
        @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, PUT");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "Origin, x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN);
    
            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() {
            }
        }
    

    并修改你的 configure(HttpSecurity http) 覆盖

    @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
            .and()
            .csrf().disable()
                .anonymous().disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/signup").permitAll()
            .antMatchers("/oauth/token").permitAll()
            .antMatchers("/fapi/**").authenticated()
            .and()
            .httpBasic()
                .realmName("MY_REALM");
        }
    

相关问题