Aurelia Keycloak 集成

Posted

技术标签:

【中文标题】Aurelia Keycloak 集成【英文标题】:Aurelia Keycloak integration 【发布时间】:2016-11-07 10:39:36 【问题描述】:

Aurelia 和 keycloak 都非常陌生,并试图让两者一起工作。使用没有 typescript 的 Aurelia 生产种子

我正在尝试遵循这个使用 Angular2 keycloak-angular2 的示例

该仓库中还有一个 angular1 示例

到目前为止采取的步骤(我已经更新了代码 sn-p 并增加了进度)

1) 添加 bower-jspm 端点并安装 keycloak.js

2) 添加了 keycloak-service.js(更新)

```
import keycloak from 'keycloak';
import LogManager from 'aurelia-framework';

let logger = LogManager.getLogger('KeycloakService');

export class KeycloakService 
  static auth = ;

  static init()  
    let keycloakAuth = new Keycloak(
      "realm": "my-realm",
      "url": "http://localhost:8080/auth",
      "ssl-required": "external",
      "clientId": "CID"
    );

    KeycloakService.auth.loggedIn = false;

    return new Promise(function(resolve, reject) 
      keycloakAuth.init( onLoad: 'login-required' )
        .success(() => 
          logger.debug("Init Success");
          KeycloakService.auth.loggedIn = true;
          KeycloakService.auth.authz = keycloakAuth;
          KeycloakService.auth.logoutUrl = keycloakAuth.authServerUrl  + "/realms/my-realm/tokens/logout?redirect_uri=/";
          resolve(null);
        )
       .error(() => 
          logger.debug("Init Failed");
          reject(null)
       );
    );
   

  logout()
    logger.debug("Logging out");
    KeycloakService.auth.loggedIn = false;
    KeycloakService.auth.authz = null;
    window.location.href = KeycloakService.auth.logoutUrl;
  

  getToken() 
   return new Promise(function(resolve, reject) 
     if (KeycloakService.auth.authz.token) 
        logger.debug("Refreshing token");
        KeycloakService.auth.authz.updateToken(5)
          .success(function() 
            logger.debug("Token refreshed");
            resolve(KeycloakService.auth.authz.token);
          )
         .error(function() 
            logger.debug("Failed to refresh token");
            reject('Failed to refresh token');
         );
     
   );
 

```

3)在main.js(更新)中,

```
import KeycloakService from 'keycloak-service';
export function configure(aurelia) 
  aurelia.use
    .standardConfiguration()
    .developmentLogging();


  KeycloakService.init()
    .then(() => aurelia.start().then(() => aurelia.setRoot()));

```

当我转到 localhost:9000 时,它会将我重定向到登录页面,并允许我登录并将我带到欢迎页面。每次我刷新 localhost:9000 页面时,它都不记得我以前的登录信息(即使我的 keycloak 会话处于活动状态)并强制我再次登录。我猜这是由于需要加载登录。虽然它不应该记得我已经登录了吗?

登录后,控制台在 checkLoginIframe 上显示错误“keycloak.js:828 Uncaught TypeError: Cannot read property 'postMessage' of null”。

不知道如何实现路由/http拦截器

我尝试创建一个简单的类来访问服务器上的健康端点

```
import inject from 'aurelia-framework';
import HttpClient from 'aurelia-fetch-client';
import KeycloakService from 'keycloak-service';
import LogManager from 'aurelia-framework';
import 'fetch';

let logger = LogManager.getLogger('health');

@inject(HttpClient, KeycloakService)
export class Health 
  constructor(http, keycloakService) 
    http.configure(config => 
      config
      .useStandardConfiguration()
      .withBaseUrl('http://localhost:8081/api/health/')
      .withDefaults(
        headers: 
          'X-Requested-With': 'Fetch'
        
      );
  );

    this.http = http;
    this.keycloakService = keycloakService;
  

  activate() 
    return this.keycloakService.getToken().then(
      token => 
        // Somehow add this token to the header ...
        this.http.fetch('summary').then(response => response.json())
      
    );
  

```

但是,这再次失败并出现相同的 checkLoginIFrame 问题。也不确定此时我将如何注入不记名令牌标头。有没有更好的方法来全局拦截(或半全局拦截某些路由)或者我应该创建一个超类并使用它扩展所有需要向服务器发送令牌的服务。

我正试图到达一个欢迎屏幕不安全的地步,并且可能是一个不安全的搜索屏幕,(所以我不会做 onLoad: 'login-required'。我想有一个明确的链接在主页上登录/注册。其余导航需要用户登录

有没有人成功实现了这一点并且可以分享一些代码?正如我所说,主要是具有有限 angular 1 经验和评估 keycloak 的服务器端开发人员,以及所有这些东西几乎是未知的水域

哦,我不能直接从 keycloak 控制台安装选项卡中复制 keycloak.json,必须将“resource”更改为“clientId”,将“auth-server-url”更改为“url”,这是正常行为吗?

---- 更新----

所以在调试之后,document.body.appendChild(iframe); 确实在 iframe 上设置了 contentWindow,但是当间隔到期后调用checkLoginIframe 时,contentWindow 出于某种原因更改为 null。我想这与我何时执行 init 与 aurelia 何时完成它的事情有关,我尝试在不同的点调用 init,但随后路由器妨碍了事情。由于我不需要在 init 上加载,我只需在 main.js 中的 configure 上执行 init,至少现在这个问题消失了。

以 keycloak 中的 js-console 演示为例,我正在尝试实现显式登录。登录按钮将我带到 keycloak 登录页面,但是在登录时,我现在遇到的问题是 aurelia 路由器抱怨“错误:找不到路由:http://localhost:9000/?redirect_fragment=%2Fkcr#state=...&code=...”,其中 kcr 是 html/我用来在屏幕上放置一些按钮以测试功能的 js 路由模块

谢谢

【问题讨论】:

【参考方案1】:

使用

初始化 Keycloak
keycloakAuth.init(onLoad: 'login-required', checkLoginIframe: false)

为我解决了这个问题。

原因似乎是 checkLoginIframe 元素只有在配置onLoad: 'check-sso' 时才能正确创建并添加到 dom 中。但这只是通过keycloak.js 查看和调试得到的猜测。如果我的猜测是正确的,keycloak.js 应该会得到更好的配置错误处理。

【讨论】:

【参考方案2】:

见Aurelia-Keycloak。

Aurelia-Keycloak

Alpha 版本。基于 KeyCloak 的身份验证插件,适用于 Aurelia 应用程序。

开始

安装 Aurelia-Keycloak:

jspm 安装 aurelia-keycloak

添加keycloak配置和初始化设置:

按照 Keycloak 说明创建 keycloak.json 配置文件。将此文件放在与应用程序的 index.html 文件相同的目录中。有关其初始化选项和 API,请参阅 keycloak javascript 适配器 documentation。

将插件添加到您应用的 main.js。此示例假定您的 keycloak.json 位于您的根目录中。此代码将立即导致登录屏幕出现。.plugin('aurelia-keycloak', initOptions: onLoad: 'login-required' ) 要延迟登录,请使用以下命令: .plugin('aurelia-keycloak') 然后,在您的代码中构造一个登录按钮来调用 keycloak 登录函数。 您可以插入带有插件声明的安装配置,而不是使用 keycloak.json 文件

`.plugin('aurelia-keycloak',install:PASTE GENERATED KEYCLOAK.JSON HERE,initOptions: onLoad: 'login-required'

详见 GITHUB。

【讨论】:

我安装了插件,然后将“aurelia-keycloak.js”复制到 ../jspm_packages/github/waynepennington/ 并将其重命名为“aurelia-keycloak@master.js”。但是它找不到 "http://localhost:9000/jspm_packages/github/waynepennington/aurelia-keycloak@master/aurelia-keycloak.js. 。所以我尝试将其更改为module.exports = require("github:waynepennington/aurelia-keycloak@master/aurelia-keycloak"); 并将“aurelia-keycloak,js”放在其查找的子目录中。然后我得到aurelia-pal.js:38 Uncaught (in promise) Error: Error invoking ViewSlot. Check the inner error for details. 我现在正在调查这个。问题可能与它被 jspm'd 作为“功能”而不是“插件”有关。这会导致 Aurelia 查找随附的 html 文件。所以一个,要么使用“noView”装饰器,所以它不会寻找 html。或者,就像为 Aurelia Plugin Skeleton 所做的那样,放入一个假的 html 文件。我今天会尝试解决这个问题。 为了加快速度,暂时将开发切换到 aurelia “功能”而不是“插件”。我会给你那个代码。 谢谢,我很感激。另外,如果您没有机会查看我原始帖子的更新,您对当 keycloak 在执行显式登录而不是加载时重定向回 aurelia 时找不到路由问题有任何想法吗?还要感谢您指出帮助很大的 js-console 示例,我最初错过了这一点,因为我只是在他们的 repo 的 demo-templates 子目录中查看 至少让重定向回到 aurelia 工作,不得不将 keycloak "init" 的 responseMode 从 fragment 更改为 query。需要深入了解这意味着什么,但至少能够成功登录并返回应用程序。仍在努力找出如何以一种很好的方式拦截和执行 refreshToken 以及重定向回提示登录的最后一个访问页面而不是根页面。

以上是关于Aurelia Keycloak 集成的主要内容,如果未能解决你的问题,请参考以下文章

使用 SMS 进行用户验证的 Keycloak

Keycloak - 如何允许在没有注册的情况下链接帐户

Keycloak IdP SAML2 将 XML 元数据导出到 SP

带有 https 的负载均衡器后面的 Keycloak Docker 失败

“无法连接到数据库”:Keycloak Operator 外部数据库配置不起作用

Swagger 中的 Keycloak 集成