Доступ к XMLHttpRequest по адресу "http://localhost:..." из источника "http://localhost:4200" заблокирован политикой CORS
Я устанавливаю безопасную конфигурацию с Keycloak и Kong для углового API.
Я следил за следующим учебником https://www.jerney.io/secure-apis-kong-keycloak-1/, но в конце я получаю следующую ошибку:
Доступ к XMLHttpRequest по адресу "http://localhost:8000/ops/warehouses" из источника "http://localhost:4200" был заблокирован политикой CORS: Ответ на предварительный запрос не проходит проверку контроля доступа: Перенаправление не выполняется разрешено для предполетного запроса.
У меня есть угловой API, который подключается к бэкэнд-API в машинописи. Поэтому я хочу защитить весь API-интерфейс с помощью Keycloak.
Я использую Kong в качестве шлюза API, а Konga - в качестве интерфейса для администрирования Kong.
Интеграция Keycloak с Kong осуществляется через плагин OIDC https://github.com/nokia/kong-oidc
Моя текущая версия Keycloak - 6.0.1, версия Kong - 1.2.1 и Konga 0.14.3. И я внедряю каждый из этих элементов в контейнеры с помощью Docker.
Мое угловое приложение использует npm install keycloak-js --save, и я следую следующей конфигурации https://medium.com/@blained3/connecting-keycloak-to-angular-d175c92a0dd3
Это конфигурация docker compose:
//docker-compose.yml
version: '3.4'
networks:
kong_network:
volumes:
kong-datastore:
keycloak-datastore:
services:
kong-db:
image: postgres:9.6
restart: always
volumes:
- kong-datastore:/var/lib/postgresql/data
networks:
- kong_network
ports:
- "15432:5432"
environment:
POSTGRES_DB: kong
POSTGRES_USER: kong
POSTGRES_PASSWORD:
healthcheck:
test: ["CMD", "pg_isready", "-U", "kong"]
interval: 5s
timeout: 5s
retries: 5
kong-migration:
build: .
command: "kong migrations bootstrap"
networks:
- kong_network
restart: on-failure
environment:
KONG_PG_HOST: kong-db
links:
- kong-db
depends_on:
- kong-db
kong:
build: .
restart: always
depends_on:
- kong-migration
- kong-db
healthcheck:
test: ["CMD", "curl", "-f", "http://kong:8001"]
interval: 5s
timeout: 2s
retries: 15
networks:
- kong_network
ports:
- "8000:8000" # Listener
- "8001:8001" # Admin API
- "8443:8443" # Listener (SSL)
- "8444:8444" # Admin API (SSL)
extra_hosts:
- "keycloak-host:192.168.18.247"
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-db
KONG_PG_PORT: 5432
KONG_PG_DATABASE: kong
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
KONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl
KONG_PLUGINS: oidc
keycloak-db:
image: postgres:9.6
volumes:
- keycloak-datastore:/var/lib/postresql/data
networks:
- kong_network
ports:
- "25432:5432"
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
keycloak:
image: jboss/keycloak:4.5.0.Final
restart: always
depends_on:
- keycloak-db
networks:
- kong_network
ports:
- "8180:8080"
environment:
DB_VENDOR: POSTGRES
DB_ADDR: keycloak-db
DB_PORT: 5432
DB_DATABASE: keycloak
DB_USER: keycloak
DB_PASSWORD: password
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
// Dockerfile
FROM kong:1.1.2-alpine
RUN apk update && apk add git unzip curl
ENV KONG_PLUGINS="bundled, oidc"
RUN luarocks install kong-oidc
// Конг-конфигурация через Конгу
Konga работает в порту 1337, администратор Kong в 8001 и клиент Kong в 8000
Итак, я сделал создать сервис со следующей конфигурацией:
{
"host": "192.168.18.247",
"created_at": 1565303126,
"connect_timeout": 60000,
"id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
"protocol": "http",
"name": "ops",
"read_timeout": 60000,
"port": 3000,
"path": "/api",
"updated_at": 1565303147,
"retries": 5,
"write_timeout": 60000,
"tags": null,
"extras": {
"createdUser": null,
"updatedUser": null,
"kong_node_id": "1",
"service_id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
"createdAt": "2019-08-08T22:25:26.319Z",
"updatedAt": "2019-08-08T22:25:47.349Z",
"id": 1
}
}
К этому сервису я добавил следующий маршрут:
{
"updated_at": 1565303167,
"created_at": 1565303167,
"strip_path": true,
"snis": null,
"hosts": null,
"name": "ops",
"methods": null,
"sources": null,
"preserve_host": false,
"regex_priority": 0,
"service": {
"host": "192.168.18.247",
"created_at": 1565303126,
"connect_timeout": 60000,
"id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
"protocol": "http",
"name": "ops",
"read_timeout": 60000,
"port": 3000,
"path": "/api",
"updated_at": 1565303147,
"retries": 5,
"write_timeout": 60000,
"tags": null,
"extras": {
"createdUser": null,
"updatedUser": null,
"kong_node_id": "1",
"service_id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
"createdAt": "2019-08-08T22:25:26.319Z",
"updatedAt": "2019-08-08T22:25:47.349Z",
"id": 1
}
},
"paths": [
"/ops"
],
"destinations": null,
"id": "1e0ba28b-da93-44d1-9433-ea2bf03340d6",
"protocols": [
"http",
"https"
],
"tags": null
}
Мой плагин OIDC:
{
"created_at": 1564164342,
"config": {
"response_type": "code",
"introspection_endpoint": "http://keycloak-host:8180/auth/realms/master/protocol/openid-connect/token/introspect",
"filters": null,
"bearer_only": "true",
"ssl_verify": "no",
"session_secret": null,
"introspection_endpoint_auth_method": null,
"realm": "master",
"redirect_after_logout_uri": "/",
"scope": "openid",
"token_endpoint_auth_method": "client_secret_post",
"logout_path": "/logout",
"client_id": "back",
"client_secret": "b1f34901-becc-4f6a-a586-258fef04569c",
"discovery": "http://keycloak-host:8180/auth/realms/master/.well-known/openid-configuration",
"recovery_page_path": null,
"redirect_uri_path": null
},
"id": "bc77d4d7-9fdb-4267-8997-a8187c182ecc",
"service": null,
"name": "oidc",
"protocols": [
"http",
"https"
],
"enabled": true,
"run_on": "first",
"consumer": null,
"route": null,
"tags": null
}
Моя конфигурация в Keycloak следующая:
Я создал двух клиентов, один для внешнего интерфейса, а другой для моего внешнего интерфейса.
//ФРОНТ
{
"realm": "MyDemo",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "front",
"public-client": true,
"confidential-port": 0
}
// НАЗАД
{
"realm": "MyDemo",
"bearer-only": true,
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "back",
"credentials": {
"secret": "20f3bcf1-683d-4e1c-98a6-414877e461db"
},
"confidential-port": 0,
"policy-enforcer": {}
}
В моем внешнем интерфейсе я настроил свой URL для внутреннего интерфейса:
export const API = {
'uri': 'http://localhost:8000/ops/'
};
И я создал два файла для управления службой keycloak:
//keycloak.service.ts
import { Injectable } from '@angular/core';
declare var Keycloak: any;
@Injectable({
providedIn: 'root'
})
export class KeycloakService {
public keycloakAuth: any;
constructor() { }
init(): Promise<any> {
return new Promise((resolve, reject) => {
const config = {
'url': 'http://keycloak-host:8180/auth',
'realm': 'master',
'clientId': 'front',
'credentials': {
'secret': 'd030874e-41bc-4710-b28f-c568e7e66c66'
},
};
this.keycloakAuth = new Keycloak(config);
this.keycloakAuth.init({ onLoad: 'login-required' })
.success(() => {
resolve();
})
.error(() => {
reject();
});
});
}
getToken(): string {
return this.keycloakAuth.token;
}
}
//token.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpHeaders
} from '@angular/common/http';
import { KeycloakService } from './keycloak.service';
import { Observable } from 'rxjs';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private kcService: KeycloakService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log("BIngo!!!!!!!!!");
const authToken = this.kcService.getToken() || '';
request = request.clone({
// setHeaders: {
// 'Authorization': 'Bearer ' + authToken
// }
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + authToken
})
});
console.log(authToken);
return next.handle(request);
}
}