独立Spring OAuth2 JWT授权服务器+ CORS

时间:2015-06-03 22:52:33

标签: spring-security cors jwt spring-security-oauth2

所以我从Dave Syer的this example压缩了以下授权服务器

@SpringBootApplication
public class AuthserverApplication {

    public static void main(String[] args) {
            SpringApplication.run(AuthserverApplication.class, args);
    }

    /* added later
    @Configuration
    @Order(Ordered.HIGHEST_PRECEDENCE)
    protected static class MyWebSecurity extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http //.csrf().disable() 
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
       }
    }*/

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2AuthorizationConfig extends
                    AuthorizationServerConfigurerAdapter {

            @Autowired
            private AuthenticationManager authenticationManager;

            @Bean
            public JwtAccessTokenConverter jwtAccessTokenConverter() {
                    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                    KeyPair keyPair = new KeyStoreKeyFactory(
                                    new ClassPathResource("keystore.jks"), "foobar".toCharArray())
                                    .getKeyPair("test");
                    converter.setKeyPair(keyPair);
                    return converter;
            }

            @Override
            public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
                    clients.inMemory()
                                    .withClient("acme")
                                    //.secret("acmesecret")
                                    .authorizedGrantTypes(//"authorization_code", "refresh_token",
                                                    "password").scopes("openid");
            }

            @Override
            public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                            throws Exception {
                    endpoints.authenticationManager(authenticationManager).accessTokenConverter(
                                    jwtAccessTokenConverter());
            }

            @Override
            public void configure(AuthorizationServerSecurityConfigurer oauthServer)
                            throws Exception {
                    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
                                    "isAuthenticated()");
            }
    }
}

当我运行它并用curl测试它

curl acme@localhost:8110/oauth/token -d grant_type=password -d client_id=acme -d username=user -d password=password

我得到一个JWT作为响应,但是一旦我尝试从我的前端(Angular JS在不同的端口上)访问AuthServer,我就会收到CORS错误。不是因为缺少Headers,而是因为OPTION请求被拒绝并且缺少凭证。

Request URL:http://localhost:8110/oauth/token
Request Method:OPTIONS
Status Code:401 Unauthorized
WWW-Authenticate:Bearer realm="oauth", error="unauthorized", error_description="Full authentication is required to access this resource"

我已经知道我必须添加一个CorsFilter并另外找到this post我在第一个答案中使用该片段让OPTIONS请求访问/oauth/token而没有凭据:

@Order(-1)
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
   @Override
   protected void configure(HttpSecurity http) throws Exception {
       http
          .authorizeRequests()
          .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
   }
}

之后我卷曲了以下错误:

{"timestamp":1433370068120,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/oauth/token"}

为了简单起见,我刚刚将http.csrf().disable()添加到MyWebSecurity类的configure方法中,该方法解决了OPTION请求的问题,但因此POST请求不再有效,我得到There is no client authentication. Try adding an appropriate authentication filter.(也有卷曲)。

我试图找出是否必须以某种方式连接MyWebSecurity类和AuthServer,但没有任何运气。原始示例(开头的链接)也注入了authenticationManager,但这对我没有任何改变。

6 个答案:

答案 0 :(得分:87)

找到问题的原因!

如果CorsFilter处理了OPTIONS请求,我只需要结束过滤链并立即返回结果!

SimpleCorsFilter.java

@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() {
    }
}

之后我可以忽略我的AuthServer = D

中的OPTIONS预检请求

因此,服务器的工作方式如上所述,您可以在开头忽略带有MyWebSecurity类的块注释。

答案 1 :(得分:22)

我找到了一个使用问题解决方案的解决方案。但我有另一种方式来描述解决方案:

@Configuration
public class WebSecurityGlobalConfig extends WebSecurityConfigurerAdapter {
      ....
      @Override
      public void configure(WebSecurity web) throws Exception {
        web.ignoring()
          .antMatchers(HttpMethod.OPTIONS);
      }
      ...
}

答案 2 :(得分:10)

我使用以下

遇到了类似的问题
  • 后端Spring Boot 1.5.8.RELEASE
  • Spring OAuth2 Spring OAuth 2.2.0.RELEASE w
  • Vuejs app使用axios ajax请求库

postman一切正常!当我开始从Vuejs应用程序发出请求时,我收到以下错误

  

选项http://localhost:8080/springboot/oauth/token 401()

  

XMLHttpRequest无法加载http://localhost:8080/springboot/oauth/token。预检的响应具有无效的HTTP状态代码401

在阅读了一下后,我发现我可以通过覆盖Spring OAuth实施类中的OPTIONS来指示我的configure忽略WebSecurityConfigurerAdapter请求,如下所示

@Override
public void configure(WebSecurity web) throws Exception {
   web.ignoring().antMatchers(HttpMethod.OPTIONS);
}

上述内容有所帮助,但后来我遇到了CORS特定错误

  

选项http://localhost:8080/springboot/oauth/token 403()

  

XMLHttpRequest无法加载http://localhost:8080/springboot/oauth/token。对预检请求的响应没有通过访问控制检查:否'访问控制 - 允许 - 来源'标头出现在请求的资源上。起源' http://localhost:8000'因此不允许访问。响应的HTTP状态代码为403。

并在CorsConfig的帮助下解决了上述问题,如下所示

@Configuration
public class CorsConfig {
    @Bean
    public FilterRegistrationBean corsFilterRegistrationBean() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.applyPermitDefaultValues();
        config.setAllowCredentials(true);
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setAllowedMethods(Arrays.asList("*"));
        config.setExposedHeaders(Arrays.asList("content-length"));
        config.setMaxAge(3600L);
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
}

添加上述类后,它按预期工作。在我去prod之前,我将研究consequences使用

web.ignoring().antMatchers(HttpMethod.OPTIONS);

对于上述best practices配置,

以及Cors。目前*完成了这项工作,但绝对不能保证生产安全。

Cyril的回答帮助了我partially然后我在Github问题中遇到了CorsConfig的想法。

答案 3 :(得分:2)

好吧,你是对的!这是一个解决方案,它也适用于我(我有同样的问题)

但是我想让我使用更智能的CORS Filter实现Java: http://software.dzhuvinov.com/cors-filter.html

这是Java应用程序的完整解决方案。

实际上,您可以看到here如何解决您的观点。

答案 4 :(得分:0)

在这里使用Spring Boot 2。

我必须在AuthorizationServerConfigurerAdapter

中执行此操作
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {

    Map<String, CorsConfiguration> corsConfigMap = new HashMap<>();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    //TODO: Make configurable
    config.setAllowedOrigins(Collections.singletonList("*"));
    config.setAllowedMethods(Collections.singletonList("*"));
    config.setAllowedHeaders(Collections.singletonList("*"));
    corsConfigMap.put("/oauth/token", config);
    endpoints.getFrameworkEndpointHandlerMapping()
            .setCorsConfigurations(corsConfigMap);

    //additional settings...
}

答案 5 :(得分:0)

我尝试了其他方法来解决此问题。我要说的是,以下内容已在我这方面解决(使用Spring Boot 2)
1-Add the below method to the below method class that extends WebSecurityConfigurerAdapter:
    // CORS settings
     @Override
     public void configure(WebSecurity web) throws Exception {
       web.ignoring()
         .antMatchers(HttpMethod.OPTIONS);
     }
2-Add the below to my class that extends AuthorizationServerConfigurerAdapter
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    // enable cors for "/oauth/token"
    Map<String, CorsConfiguration> corsConfigMap = new HashMap<>();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
   
    config.setAllowedOrigins(Collections.singletonList("*"));
    config.setAllowedMethods(Collections.singletonList("*"));
    config.setAllowedHeaders(Collections.singletonList("*"));
    corsConfigMap.put("/oauth/token", config);
    endpoints.getFrameworkEndpointHandlerMapping()
            .setCorsConfigurations(corsConfigMap);
    // add the other configuration
}