首页 > 解决方案 > 从源“http://localhost:4200”访问“http://localhost:...”处的 XMLHttpRequest 已被 CORS 策略阻止

问题描述

我正在使用 Keycloak 和 Kong 为 Angular API 设置安全配置。

我正在关注下一个教程https://www.jerney.io/secure-apis-kong-keycloak-1/,但最后我得到了下一个错误:

从源“http‍://localhost:4200”访问“http‍://localhost:8000/ops/warehouses”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:重定向未通过允许预检请求。

我有一个角度 API,它连接到打字稿中的后端 API。所以我想要的是使用 Keycloak 前后保护整个 API。

我使用 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配置Kong

Konga 在 1337 端口运行 Kong admin 在 8001 和 client 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);
 }
}

标签: angulartypescriptkeycloakkong-plugin

解决方案


推荐阅读