【问题标题】:How to setup the CORS configuration in keycloak to allow an ajax request?如何在 keycloak 中设置 CORS 配置以允许 ajax 请求?
【发布时间】:2019-05-28 14:11:23
【问题描述】:

我正在尝试使用 keycloak 作为身份验证服务器。 我尝试通过 ajax 请求获取令牌。由于 CORS,它在 curl 中效果很好,但在我的角度中效果不佳。 我已将客户端设置为 Direct access grant enable 为 true,并将 * 添加到 Web Origin。

fetch("http://localhost:8080/auth/realms/master/protocol/openid-connect/token", {
  body: "grant_type=password&client_id=admin-cli&username=adrien&password=adrien&undefined=",
  headers: {
    Accept: "application/json, text/plain, */*,application/x-www-form-urlencoded",
    "Access-Control-Allow-Headers": "Origin, Content-Type, Authorization, Content-Length, X-Requested-With",
    "Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,OPTIONS",
    "Access-Control-Allow-Origin": "*",
    "Cache-Control": "no-cache",
    "Content-Type": "application/x-www-form-urlencoded",
    Dnt: "1",
    "Postman-Token": "cfd33776-882d-4850-b2e7-d66629da3826"
  },
  method: "POST"
})

你知道我错过了什么吗?

提前致谢。

【问题讨论】:

    标签: angular cors keycloak


    【解决方案1】:

    我认为您正在尝试以错误的方式使用它。有角度插件,我认为你应该使用它。所以这里是clifnotes。安装插件:

    npm i keycloak-angular
    

    然后初始化keycloack:

    import {KeycloakService} from 'keycloak-angular';
    
    export function initializer(keycloak: KeycloakService): () => Promise<any> {
      return (): Promise<any> => {
        return new Promise(async (resolve, reject) => {
          try {
            await keycloak.init({
              config: {
                url: 'http://localhost:8080/auth',
                realm: 'MySecureRealm',
                clientId: 'myAngularApplication'
              },
              initOptions: {
                onLoad: 'login-required',
                checkLoginIframe: false,
                responseMode: 'fragment',
                flow: 'standard'
              }
            });
            resolve();
          } catch (error) {
            reject(error);
          }
        });
      };
    }
    

    然后在 app.module.ts 中

    import { BrowserModule } from '@angular/platform-browser';
    import {APP_INITIALIZER, NgModule} from '@angular/core';
    
    
    import { AppComponent } from './app.component';
    import {KeycloakService} from 'keycloak-angular';
    import {initializer} from '../environments/environment';
    import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
    import {TokenInterceptor} from './token-interceptor';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        HttpClientModule
      ],
      providers: [
        KeycloakService,
        {
          provide: APP_INITIALIZER,
          useFactory: initializer,
          multi: true,
          deps: [KeycloakService]
        },
        {
          provide: HTTP_INTERCEPTORS,
          useClass: TokenInterceptor,
          multi: true
        },
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    你还需要这个 TokenInterceptor:

    import { Injectable } from '@angular/core';
    import {
      HttpRequest,
      HttpHandler,
      HttpEvent,
      HttpInterceptor
    } from '@angular/common/http';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/mergeMap';
    import 'rxjs/add/observable/fromPromise';
    
    import { KeycloakService, KeycloakAuthGuard, KeycloakAngularModule } from 'keycloak-angular';
    import {HttpHeaders} from '@angular/common/http/src/headers';
    
    @Injectable()
    export class TokenInterceptor implements HttpInterceptor {
    
      constructor(protected keycloak: KeycloakService) {}
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return Observable
          .fromPromise(this.keycloak.getToken())
          .mergeMap(
          token => {
    
            console.log('adding heder to request');
            console.log(token);
    
            const headers: HttpHeaders = req.headers;
            const hedersWithAuthorization: HttpHeaders = headers.append('Authorization', 'bearer ' + token);
            const requestWithAuthorizationHeader = req.clone({ headers: hedersWithAuthorization });
            return next.handle(requestWithAuthorizationHeader);
          }
        );
      }
    }
    

    应该这样做。当您进入应用程序但未登录时,您将被重定向到 keycloak 登录屏幕并返回您的应用程序。并且将向所有传出请求添加身份验证标头。如果您有任何问题,请告诉我,我非常了解这项技术。

    【讨论】:

    • 感谢您的快速回复,但在您的解决方案中,使用了keycloak登录页面。对于我的用例,我想使用自己的登录表单,然后通过 rest api 调用 keycloak 来检索令牌。或许不可能,唯一推荐的方式是使用keycloak登录页面
    • 有可能,但很难做到。您必须在您的应用程序中实现整个 OpenIDConnect 流程。如果你愿意,我可以帮你。但我不推荐它。设置它可能不安全的事实(您的应用程序将有权访问用户名和密码)这将需要一些时间。你能告诉我为什么你不能按原定的方式使用 keycloak 吗?作为委托授权提供者?
    • 好的,非常感谢您的解释,我将使用keycloak登录页面。我没有正当理由不使用它。
    猜你喜欢
    • 2019-07-19
    • 1970-01-01
    • 2013-09-13
    • 2023-03-14
    • 2020-11-18
    • 2020-09-12
    • 2012-07-23
    • 2020-01-17
    • 2020-11-21
    相关资源
    最近更新 更多