试用Keycloak的JavaScript客户端适配器

尝试使用Keycloak提供的OIDC客户端适配器。
虽然Keycloak的OIDC客户端适配器在WildFly、Tomcat、Node.js等多种形式上都有提供,但随着版本的升级,逐渐有些被废弃,而在最新版本(21.0.2)中,除了JavaScript以外的适配器全部都被废弃了。
本文将通过使用仅存的JavaScript客户端适配器来验证从客户端应用连接到Keycloak服务器的方法。
注意:本文是根据Keycloak的版本升级,更新了“试用Keycloak客户端适配器(Angular版)”一文。

在本文中要做的事情

    1. 创建Angular应用程序

 

    1. 配置Keycloak服务器

 

    1. 安装Keycloak客户端适配器

 

    进行功能验证

创建 Angular 应用程序

我只需要一个选项

使用 Angular 构建的客户端应用程序上,创建并验证 Keycloak 的身份验证功能,包括“必需屏幕”和“非必需屏幕”两种简单界面。

环境

Angular的开发环境如下所示。

    • Node: 16.15.1

 

    • Angular: 14.3.0

 

    Angular CLI: 14.0.7

使用Angular CLI的ng new命令创建了一个新项目,
并使用ng generate component命令创建了两个页面。

首先,将AppComponent改为可使用路由切换页面的形式,并添加所需的页面组件到路由配置中。

<nav>
  <a routerLink="">認証不要</a>
  <a routerLink="/auth">要認証</a>
</nav>
<router-outlet></router-outlet>
import { RouterModule, Routes } from '@angular/router';
import { AuthPageComponent } from './auth-page/auth-page.component';
import { NonAuthPageComponent } from './non-auth-page/non-auth-page.component';

const routes: Routes = [
  { path: '', component: NonAuthPageComponent },
  { path: 'auth', component: AuthPageComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

无需验证的页面将是以下简单的纯文本页面。
此外,Typescript文件不需要进行特别操作,保持自动生成的状态即可。

<h3>Keycloakによる認証が不要なページです。</h3>

以下是需要認證的頁面,可以顯示經過認證的使用者資訊。

<h3>Keycloakによる認証が必要なページ</h3>
<div>
  <span>User Name : {{ user.username }}</span>
  <span>First Name : {{ user.firstName }}</span>
  <span>Last Name : {{ user.lastName }}</span>
</div>
<div>
  <span>ID Token:</span>
  <div class="token">{{ user.idToken }}</div>
</div>
import { Component, OnInit } from '@angular/core';
import { User } from '../user.model';

@Component({
  selector: 'app-auth-page',
  templateUrl: './auth-page.component.html',
  styleUrls: ['./auth-page.component.scss'],
})
export class AuthPageComponent implements OnInit {
  constructor() {}

  user!: User;

  public ngOnInit(): void {}

提前创建一个包含用户信息的箱子。
※ 用户信息将从Keycloak中获取已认证用户的信息并装入,但此部分稍后会解释。

export class User {
  public username: string;
  public firstName: string;
  public lastName: string;
  public idToken: string;

  constructor(
    username: string,
    firstName: string,
    lastName: string,
    idToken: string
  ) {
    this.username = username;
    this.firstName = firstName;
    this.lastName = lastName;
    this.idToken = idToken;
  }
}

Keycloak服务器配置

建立Keycloak服务器。

我使用了Keycloak的官方网页来在本地PC上进行验证。

创建领域

一旦Keycloak启动后,请登录管理控制台并创建一个Realm。
本次创建的Realm名称为demo-realm。

步骤 (bù

レルム作成.PNG

创建客户端

为了客户端应用程序,创建 Keycloak 的客户端。
将客户端创建到之前创建的 Realm 中。

过程

クライアント作成1.PNG
クライアント作成2.PNG
由于客户端应用程序无法安全存储客户端凭据,所以需要将访问类型设置为公开。

设置以下两项并按下“保存”按钮。

    • Validate redirect URIs:http://localhost:4200/*

 

    Web origins:http://localhost:4200
クライアント作成3.PNG
「验证重定向URI」是在Keycloak认证之后设置允许用作重定向目标的URL。
「Web来源」是用于设置允许CORS请求的主机。
如果这两个值没有正确设置与执行方客户端应用程序相符,将会导致请求被拒绝或出现CORS错误,从而导致认证失败。

创建用户

创建用户以进行认证。

操作步骤

ユーザー作成1.PNG
ユーザー作成2.PNG

引入Keycloak客户端适配器。

首先,为了使用Javascript客户端适配器,您需要在项目根目录下执行以下命令。

npm install keycloak-js --save

因为在这个项目中引入了keycloak-js,所以可以在这里使用。
在每个组件中适当地引入keycloak-js并使用。

设置Keycloak连接信息

为了与Keycloak服务器进行通信,我们将在环境配置文件中设置我们先前创建的客户端信息。

export const environment = {
  production: false,
  KEYCLOAK_URL: 'http://localhost:8080/',
  KEYCLOAK_REALM: 'demo-realm',
  KEYCLOAK_CLIENTID: 'demo-client',
};

创建Keycloak服务

在这项服务中,我们将实施服务的初始化并获取用户信息的功能。

执行以下命令以创建服务。

ng generate service keycloak

为了使服务可用,以下进行添加。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { KeycloakService } from './keycloak.service';
import { AuthPageComponent } from './auth-page/auth-page.component';
import { NonAuthPageComponent } from './non-auth-page/non-auth-page.component';

@NgModule({
  declarations: [AppComponent, AuthPageComponent, NonAuthPageComponent],
  imports: [BrowserModule, AppRoutingModule],
  providers: [KeycloakService],
  bootstrap: [AppComponent],
})
export class AppModule {}

以下是实际实施的服务的整体概况。

import { Injectable } from '@angular/core';
import Keycloak from 'keycloak-js';
import { Observable } from 'rxjs';
import { environment } from '../environments/environment';
import { User } from './user.model';

@Injectable({
  providedIn: 'root',
})
export class KeycloakService {
  private kc: any;
  private auth: boolean = false;
  private user!: User;

  constructor() {
    this.kc = new Keycloak({
      url: environment.KEYCLOAK_URL,
      realm: environment.KEYCLOAK_REALM,
      clientId: environment.KEYCLOAK_CLIENTID,
    });
  }

  public init(): Observable<any> {
    return new Observable((ob) => {
      this.kc
        .init({ onLoad: 'login-required' })
        .then(() => {
          this.auth = this.kc.authenticated;
          this.kc
            .loadUserProfile()
            .then((profile: any) => {
              this.user = new User(
                profile.username,
                profile.firstName,
                profile.lastName,
                this.kc.idToken
              );
              ob.next();
            })
            .catch(() => {
              console.log('loadUserProfile error');
            });
        })
        .catch(() => {
          console.log('init error');
        });
    });
  }

  public isAuth(): boolean {
    return this.auth;
  }

  public getUser(): User {
    return this.user;
  }
}

作为服务的初始设置,通过构造函数执行以下代码来配置Keycloak服务器的环境信息。

  constructor() {
    this.kc = new Keycloak({
      url: environment.KEYCLOAK_URL,
      realm: environment.KEYCLOAK_REALM,
      clientId: environment.KEYCLOAK_CLIENTID,
    });
  }

在init()函数中进行服务的初始化。在这个init()函数中,为了调用认证功能,执行了以下代码。通过这个设置,当未经认证时会将请求重定向到keycloak服务器。

init({ onLoad: 'login-required' })

為了取得已驗證用戶的信息,我們在init()成功後執行loadUserProfile()。同時,我們還提供了一個函數getUser(),將獲取的信息填充到User中,以便服務使用者參考。

使用Keycloak服务

为了在需要进行身份验证的页面中使用已创建的Keycloak服务,您可以按照以下方式将组件添加到页面中。

import { Component, OnInit } from '@angular/core';
import { KeycloakService } from '../keycloak.service';
import { User } from '../user.model';

@Component({
  selector: 'app-auth-page',
  templateUrl: './auth-page.component.html',
  styleUrls: ['./auth-page.component.scss'],
})
export class AuthPageComponent implements OnInit {
  constructor(private ks: KeycloakService) {}

  user!: User;

  public ngOnInit(): void {
    this.ks.init().subscribe(() => {
      this.user = this.ks.getUser();
    });
  }
}

在这个组件中,我们通过在ngOnInit()中调用服务的init()方法来检查用户是否已进行过身份验证。只有当用户成功验证时,才能显示本页面。

行动验证

動作検証1.PNG
動作検証2.PNG
動作検証3.PNG

使用 Keycloak 的 JavaScript 客户端适配器,我们可以验证客户端应用程序可以与 Keycloak 服务器进行交互。

最终

本次我们为了验证设定了需要授权的界面和不需要授权的界面进行操作验证,但在实际的SPA中,一旦获取了访问令牌,认证方面通常是在API端进行操作。
接下来,我想要验证诸如使用Keycloak和API网关等方式来控制SPA对API的访问等。

请参考以下资料。

以下是用中文对以上文本进行释义:

https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
https://www.npmjs.com/package/keycloak-js

广告
将在 10 秒后关闭
bannerAds