Keyclloak CORS фильтр spring boot

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

Файл Application.java в spring загрузке выглядит как

@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("*");
            }
        };
    }
} 

Свойства keycloak в файле application.properties выглядят как

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/*

Образец API REST, который я вызываю

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

свойства keyclay.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.

Ответ 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;
}

Вот как я настроил его, чтобы принять все исходные приложения, но если вы измените несколько параметров, вы сможете реплицировать то, что хотите. то есть. если вы хотите добавить только те методы, которые вы упомянули, соедините несколько addAllowedMethod(). Допустимое происхождение будет одинаковым, а затем ваш addMapping("/api/*") станет source.registerCorsConfiguration("/api/*", config);.

Edit:

Spring Сохранение данных и коррекция

Взгляните на это. Себастьян находится в команде разработчиков Spring, так что это примерно так же хорошо, как вы собираетесь получить официальный ответ.

Ответ 2

У меня нет доступа к примерам кода, но на основе конфигураций кода, которые вы включили, похоже, что отсутствующая конфигурация вызывает spring исключение заголовков CORS.

J. Ответ на Запад аналогичен недавним проблемам, с которыми я столкнулся с spring и CORS, однако я бы посоветовал вам изучить, в какую реализацию ссылаются примеры spring, потому что их два. Spring Безопасность и Spring Аннотации MVC, Обе эти реализации работают независимо друг от друга и не могут быть объединены.

При использовании подхода, основанного на фильтрах, как вы (даже сварили), ключ должен был установить учетные данные в true, чтобы заголовки аутентификации были отправлены браузером через домены. Я бы также посоветовал использовать предложенный выше метод полного кода, так как это позволит вам создать гораздо более настраиваемое веб-приложение для развертывания в нескольких доменах или средах путем вставки свойств или реестра служб.

Ответ 3

Заголовок

Access-Control-Allow-Origin должен быть установлен сервером на основе заголовка запроса Origin, предоставленного в запросе серверному приложению. Обычно браузеры задают заголовок Origin в запросе всякий раз, когда они ощущают запрос на перекрестный поиск. И они ожидают заголовок Access-Control-Allow-Origin, чтобы разрешить его.

Теперь, для keyclay, я боролся с той же проблемой. Глядя на 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

Я использую тип предоставления учетных данных клиента; поэтому я добавил его только в buildClientCredentialsGrant в TokenEndpoint.java#L473.

Мне еще нужно сделать еще несколько дайвингов кода, чтобы точно сказать, что это ошибка для успешных ответов на хорошо и найти лучшее место для установки этого на клиентском объекте в коде keyclayak (например, когда клиентский объект строится)

Вы можете попробовать.

UPDATE:
Я беру это обратно. Я перерегистрировал своего клиента в keycloak с URL-адресом Root как http://localhost:9000 (это мой внешний интерфейс приложения), и я начал получать правильные заголовки ответов на управление доступом. Надеюсь, это поможет вам.

Ответ 4

Когда ваш клиент отправляет заголовок аутентификации, вы не можете использовать allowedOrigins ( "*" ). Вы должны настроить определенный исходный URL.

Ответ 5

Я пришел сюда с той же проблемой и исправил ее, пропуская аутентификацию только для метода OPTIONS, например так:

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

Это сработало для меня, потому что запрос опций Keycloack, не включает заголовок аутентификации.

ОБНОВЛЕНИЕ Было что-то с моим кешем браузера, поэтому я не мог видеть реальное влияние изменений в моем бэкэнд-коде. Похоже, что для меня действительно работало включение всех источников CORS на уровне @RestController, например:

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