keycloak CORS 过滤器弹簧靴

Posted

技术标签:

【中文标题】keycloak CORS 过滤器弹簧靴【英文标题】:keycloak CORS filter spring boot 【发布时间】:2017-04-29 11:56:54 【问题描述】:

我正在使用 keycloak 来保护我的休息服务。我指的是给定here 的教程。我创建了其余部分和前端。现在,当我在后端添加 keycloak 时,当我的前端调用 api 时出现 CORS 错误。

Spring Boot 中的 Application.java 文件看起来像

@SpringBootApplication
public class Application 

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

    @Bean
    public WebMvcConfigurer corsConfiguration() 
        return new WebMvcConfigurerAdapter() 
            @Override
            public void addCorsMappings(CorsRegistry registry) 
                registry.addMapping("/api/*")
                        .allowedMethods(HttpMethod.GET.toString(), HttpMethod.POST.toString(),
                                HttpMethod.PUT.toString(), HttpMethod.DELETE.toString(), HttpMethod.OPTIONS.toString())
                        .allowedOrigins("*");
            
        ;
    
 

application.properties 文件中的 keycloak 属性如下所示

keycloak.realm = demo
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = tutorial-backend
keycloak.bearer-only = true
keycloak.credentials.secret = 123123-1231231-123123-1231
keycloak.cors = true
keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = admin
keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = user
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*

我正在调用的示例 REST API

@RestController
public class SampleController     
    @RequestMapping(value ="/api/getSample",method=RequestMethod.GET)
    public string home() 
        return new string("demo");
            

前端keycloak.json属性包括


  "realm": "demo",
  "auth-server-url": "http://localhost:8080/auth",
  "ssl-required": "external",
  "resource": "tutorial-frontend",
  "public-client": true

我得到的 CORS 错误

XMLHttpRequest cannot load http://localhost:8090/api/getSample. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 401.

【问题讨论】:

您可能更喜欢问一个具体的问题。否则,您可能会得到对您无效的答案。 你能提供整个堆栈跟踪吗? 服务器端没有错误。因此没有堆栈跟踪。当我的 angularJS 应用程序进行其余调用时,客户端出现错误我在浏览器控制台上收到 CORS 错误 你解决了这个问题吗?我有同样的问题 您解决了这个问题吗?我也遇到了同样的问题。 【参考方案1】:

尝试像我的示例一样创建您的 CORS bean。我最近经历了同样的事情(让 CORS 工作),这是一场噩梦,因为 SpringBoot CORS 支持目前不如 MVC CORS 强大或简单。

@Bean
public FilterRegistrationBean corsFilter() 
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);

    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;

这就是我设置它以接受任何原始应用程序范围的方式,但是如果您更改一些参数,您应该能够复制您想要的内容。 IE。如果您只想添加您提到的方法,请链接一些addAllowedMethod()。允许的来源将相同,然后您的 addMapping("/api/*") 将变为 source.registerCorsConfiguration("/api/*", config);

编辑:

Spring Data Rest and Cors

看看这个。 Sebastian 是 Spring 工程团队的一员,所以这与您将获得的官方答案一样好。

【讨论】:

下周假期回来后,我一定会告诉你的 将我的 bean 更改为您发布的内容不起作用。我认为我尝试使用 spring mvc 而根本不使用 spring boot【参考方案2】:

我知道.. 问题很老了。 但是,如果您在使用 Spring Boot + Keycloak 进行本地开发时遇到问题,您可以使用 Config

keycloak.cors=true

在您的 application.properties 中。

干杯:)

【讨论】:

为我工作!如果您并不真正关心 CORS(例如构建一个应用程序来学习像我这样的东西),那就是要走的路。我还使用RepositoryRestConfigurer 禁用了CORS,就像这里***.com/a/60014831/9134945【参考方案3】:

我无权访问代码示例,但根据您包含的代码配置,似乎缺少配置会导致 spring 排除 CORS 标头。

J。 West 的回应类似于我最近遇到的 Spring 和 CORS 问题,但是我会提醒您查看 Spring 示例引用的实现,因为有两个。 Spring Security 和 Spring MVC Annotations。这两种实现相互独立,不能组合使用。

当您使用基于过滤器的方法时(甚至归结为),关键是将允许凭据设置为 true,以便浏览器跨域发送身份验证标头。我还建议使用上面提出的完整代码方法,因为这将允许您通过属性注入或服务注册表创建一个可配置得多的 Web 应用程序,以便在多个域或环境中进行部署。

【讨论】:

注释的要点。我编辑了我的答案,以包含一个指向 Spring 工程师活跃的类似问题的链接。如果你有同样的问题,我猜你在某个时候遇到过。【参考方案4】:

Access-Control-Allow-Origin 标头应该由服务器应用程序根据向服务器应用程序的请求中提供的Origin 请求标头设置。通常,浏览器在感知到跨源请求时会在请求中设置Origin 标头。他们希望有一个Access-Control-Allow-Origin 标头作为响应以允许它。

现在,对于 keycloak,我遇到了同样的问题。查看this,似乎keycloak 没有添加Access-Control-Allow-Origin 标头以防错误响应。但是,对我来说,即使响应成功,它也不会在响应中添加此标头。

查看代码并添加断点,我注意到客户端对象的 webOrigin 没有从 Origin 标头中填充,即使已通过,因此 CORS 没有添加访问控制响应标头。

我能够通过在 CORS 构建调用之前添加以下代码行来使其工作:

client.addWebOrigin(headers.getRequestHeader("Origin").get(0));

之前:

Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();

一旦我使用此更改构建代码并启动服务器,我就开始获取三个访问控制响应标头:

Access-Control-Expose-Headers: Access-Control-Allow-Methods 
Access-Control-Allow-Origin: http://localhost:9000 
Access-Control-Allow-Credentials: true

我正在使用客户端凭据授予类型;因此我只在buildClientCredentialsGrantTokenEndpoint.java#L473 中添加了它。

我仍然需要做更多的代码潜水,以便确定这是一个成功响应的错误,并找到一个更好的位置在 keycloak 代码中的客户端对象上设置它(比如客户端对象在哪里正在建设中)

欢迎您试一试。

更新: 我收回这个。我在 keycloak 中重新注册了我的客户端,根 URL 为http://localhost:9000(这是我的前端的应用程序端口),我开始获取正确的访问控制响应标头。希望对您有所帮助。

【讨论】:

【参考方案5】:

我来到这里时遇到了同样的问题并修复了它,只对 OPTIONS 方法省略了身份验证,如下所示:

keycloak.securityConstraints[0].security-collections[0].omitted-methods[0]=OPTIONS

它对我有用,因为 OPTIONS 请求 Keycloack 确实,不包括身份验证标头。

更新 我的浏览器缓存有问题,所以我看不到后端代码更改的真正影响。看起来真正对我有用的是在 @RestController 级别启用所有 CORS 起源,如下所示:

@CrossOrigin(origins = "*")
@RestController
public class UsersApi ...

【讨论】:

【参考方案6】:

我知道问题太老了,但是我找到了更好的解决方案。 Read more at official documentation

在您的 application.yml 文件中

keycloak:
  auth-server-url: http://localhost:8180/auth
  realm: CollageERP
  resource: collage-erp-web
  public-client: true
  use-resource-role-mappings: true
  cors: true
  cors-max-age: 0
  principal-attribute: preferred_username
  cors-allowed-methods: POST, PUT, DELETE, GET
  cors-allowed-headers: X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers  

或者您可以使用 application.properties 文件进行配置

  keycloak.auth-server-url= http://localhost:8180/auth
  keycloak.realm= CollageERP
  keycloak.resource= collage-erp-web
  keycloak.public-client= true
  keycloak.use-resource-role-mappings= true
  keycloak.cors= true
  keycloak.cors-max-age= 0
  keycloak.principal-attribute= preferred_username
  keycloak.cors-allowed-methods= POST, PUT, DELETE, GET
  keycloak.cors-allowed-headers= X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers  

还有我的 java adaper 类

import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

import javax.ws.rs.HttpMethod;

@KeycloakConfiguration
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        super.configure(http);
        http.cors().and().authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .antMatchers("/api/**")
                .authenticated()
                .anyRequest().permitAll();
        http.csrf().disable();
    

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) 
        auth.authenticationProvider(keycloakAuthenticationProvider());
    

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() 
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    

    @Bean
    public KeycloakConfigResolver KeycloakConfigResolver() 
        return new KeycloakSpringBootConfigResolver();
    


【讨论】:

【参考方案7】:

当您的客户端发送 Authentication 标头时,您不能使用 允许的起源(“*”)。您必须配置特定的源 URL。

【讨论】:

那行不通。我将 allowedOrigins 更改为运行客户端的 URL。在我的项目中,它在 localhost:9000 上运行。即使更改后我仍然收到错误【参考方案8】:

由于您在 application.properties 文件中设置了属性 keycloak.cors = true,因此您必须在 Keycloak 服务器中提及启用 CORS 的来源。为此,请按照以下步骤操作。

转到Clients -> Select the client (Token owner) -> Settings -> Web Origins 逐一添加来源或添加 * 以允许所有来源。 完成此操作后,您必须获得一个新令牌。 (如果您解码令牌,您将看到您的来源为allowed-origins": ["*"]

设置属性keycloak.cors = false 是另一种选择。但这完全禁用了 CORS。

【讨论】:

以上是关于keycloak CORS 过滤器弹簧靴的主要内容,如果未能解决你的问题,请参考以下文章

弹簧靴。 HMAC 认证。如何添加自定义 AuthenticationProvider 和 Authentication 过滤器?

弹簧靴。 HMAC 认证。如何添加自定义 AuthenticationProvider 和 Authentication 过滤器?

在身份验证过滤器中添加自定义声明。在过滤器中获取用户 ID。弹簧靴

带有弹簧靴的keycloak openid单次注销

带sitemesh的弹簧靴

弹簧靴。 CORS。 'allowCredentials = false' 不起作用