Open14

学びメモ 2025/01

ebi_yuebi_yu

keycloak SPI

  • Service Provider Interface
  • keycloakの機能を拡張したい/カスタム機能を作りたい時に使用する
  • SPI実装にはProviderProviderFactoryを実装する必要がある
1. Provider インターフェース
実際の機能やロジックを提供するクラスの基盤となるインターフェース。
2. ProviderFactory インターフェース
Provider を生成および管理するための工場 (Factory) クラスの基盤となるインターフェース。

https://keycloak-documentation.openstandia.jp/22.0/ja_JP/server_development/index.html#_providers

Authenticator SPI

Keycloakの認証フローの動作をカスタマイズするためのSPI

https://www.keycloak.org/docs/latest/server_development/index.html#_auth_spi

Authenticator SPIの構成

認証SPIを実装するには、以下のインターフェイスやクラスを実装します。

  1. Authenticator: 認証ロジックの実装。
  2. AuthenticatorFactory: 認証器を生成するファクトリクラス。
  3. ProviderConfigProperty: 設定項目を定義。
  4. KeycloakSessionAuthenticationFlowContext: 認証のために必要な状態やセッション情報の管理。

Authenticator SPIの実装

Authenticator の実装

Authenticator インターフェースは、認証フロー内でユーザーの認証を行うための処理を実装します。

import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorConfigModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel;

public class MyAuthenticator implements Authenticator {

    @Override
    public void authenticate(AuthenticationFlowContext context) {
        // ユーザー認証のロジックを実装
        UserModel user = context.getUser();
        if (user != null && isUserValid(user)) {
            // 認証成功
            context.success();
        } else {
            // 認証失敗
            context.failure(AuthenticationFlowError.INVALID_CREDENTIALS);
        }
    }

    @Override
    public void action(AuthenticationFlowContext context) {
        // 追加のアクションを実装(例: ユーザー確認のための追加処理)
        context.success();
    }

    @Override
    public boolean requiresUser() {
        return true; // ユーザーが認証されている必要がある
    }

    @Override
    public boolean configuredFor(AuthenticationFlowContext context) {
        // 必要な設定がされているかを確認
        AuthenticatorConfigModel config = context.getAuthenticatorConfig();
        return config != null && config.getConfig().containsKey("my_custom_setting");
    }

    @Override
    public void close() {
        // リソース解放
    }

    private boolean isUserValid(UserModel user) {
        // ユーザーの検証ロジック(例: ユーザーが特定の条件を満たすかを確認)
        return true; // サンプルとして常に認証成功
    }
}
  • authenticate(): 認証のメインロジック。ユーザーが有効であれば context.success() を呼び出して認証を成功させます。無効であれば context.failure() を呼び出します。
  • action(): 追加アクション。認証後にさらに処理が必要であればここに記述します。
  • requiresUser(): 認証がユーザー情報に依存するかどうかを返します。ユーザーが必要な場合は true を返します。
  • configuredFor(): 認証のために必要な設定がされているかどうかを確認します。設定が正しくない場合、設定の再確認を促すことができます。

AuthenticatorFactory の実装

AuthenticatorFactory は、Authenticator を生成するためのファクトリクラスです。

import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.utils.DefaultKeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;

import java.util.ArrayList;
import java.util.List;

public class MyAuthenticatorFactory implements AuthenticatorFactory {

    private static final String ID = "my-authenticator";

    @Override
    public String getId() {
        return ID; // 認証フローで識別されるID
    }

    @Override
    public Authenticator create(KeycloakSession session) {
        return new MyAuthenticator(); // MyAuthenticator のインスタンスを作成
    }

    @Override
    public void init(Config.Scope config) {
        // 初期設定を行う
    }

    @Override
    public void postInit(KeycloakSessionFactory factory) {
        // セッションファクトリの初期化後に呼ばれる
    }

    @Override
    public void close() {
        // リソースの解放
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        // 設定項目をリストで返す
        List<ProviderConfigProperty> configProperties = new ArrayList<>();
        ProviderConfigProperty property = new ProviderConfigProperty();
        property.setName("my_custom_setting");
        property.setLabel("Custom Setting");
        property.setType(ProviderConfigProperty.STRING_TYPE);
        property.setHelpText("This is a custom setting for the authenticator.");
        configProperties.add(property);
        return configProperties;
    }
}
  • getId(): この認証器の一意なIDを返します。これは認証フロー設定で使用されます。
  • create(): MyAuthenticator のインスタンスを作成して返します。
  • init(): 初期設定を行うために使用されます。設定ファイルや環境変数から情報を取得できます。
  • getConfigProperties(): この認証器に関連する設定項目を返します。ProviderConfigProperty はKeycloakが管理する設定の項目です。ここではカスタム設定を定義しています。

SPIの統合

最後に、META-INF/services/org.keycloak.authentication.AuthenticatorFactory ファイルに AuthenticatorFactory のクラス名を記述し、Keycloakに認証SPIを認識させます。

com.example.keycloak.authenticator.MyAuthenticatorFactory

KeycloakSessionAuthenticationFlowContext の使用

  • KeycloakSession は、ユーザーやセッション情報を操作するために使用します。MyAuthenticatorauthenticate() メソッド内でセッション情報にアクセスすることができます。

  • AuthenticationFlowContext は、現在の認証フローの状態を保持し、認証結果やエラーを通知します。例えば、context.success()context.failure() を呼び出すことで、認証の結果を反映します。

ebi_yuebi_yu

Mavenのmvn installコマンドとローカルリポジトリについて

Mavenでmvn installコマンドを実行すると、ビルドされたアーティファクト(通常は.jarファイルなど)が ローカルリポジトリ にインストールされます。ローカルリポジトリは、通常ユーザーのホームディレクトリ内にある .m2 フォルダに格納されます。

1. 依存関係の解決

mvn installは、プロジェクトの依存関係をリモートリポジトリ(Maven Centralやその他のリポジトリ)からダウンロードし、ローカルリポジトリ(~/.m2/repository)にキャッシュします。

2. ビルドとインストール

ビルドが完了した後、生成されたアーティファクト(例:my-app-1.0.0.jar)は、ローカルリポジトリにインストールされます。インストールされる場所は、~/.m2/repository/ 内の適切なディレクトリに基づいており、次のようなパスで格納されます:

~/.m2/repository/com/example/my-app/1.0.0/my-app-1.0.0.jar

まとめ

  • mvn install はプロジェクトをビルドし、生成されたアーティファクトをローカルリポジトリにインストールします。
  • 依存関係がリモートリポジトリからローカルリポジトリにダウンロードされ、キャッシュされます。
  • インストールされたアーティファクトは、他のプロジェクトでも再利用可能です。
ebi_yuebi_yu

Jest.mockでのCannot access '******' before initialization回避

エラー原因と解決方法

  • エラー原因
    初期化前の testToken を参照してしまう。

  • 解決方法
    遅延評価を利用し、以下のように修正する。

jest.mock('jwt-decode', () => {
    return {
        // ダメな例 :  jwtDecode: jest.fn().mockReturnValue(tetstToken)
        jwtDecode: jest.fn(() => testToken), // 呼び出し時に testToken を評価
    };
});
  • ポイント
    • mockReturnValue は即時評価。
    • jest.fn(() => testToken) は関数実行時に評価されるため、初期化順序の問題を回避できる。
ebi_yuebi_yu

フロントエンドJSから参照できないヘッダーもある

  • 基本的にAccess-Control-Expose-Headersレスポンスヘッダーに設定がないヘッダーはブラウザで実行されるJSからは参照できない
  • CORSポリシーによって制限されている
  • 以下のヘッダーはデフォルトで公開されている
    • Cache-Control
    • Content-Language
    • Content-Length
    • Content-Type
    • Expires
    • Last-Modified
    • Pragma
  • Access-Control-Expose-Headersレスポンスヘッダーへの設定方法は以下
Access-Control-Expose-Headers: <header-name>, <header-name>, ...
Access-Control-Expose-Headers: *

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

ebi_yuebi_yu

CORS(Cross-Origin Resource Sharing)の歴史と仕組み

CORS(Cross-Origin Resource Sharing)は、Webブラウザのセキュリティ機構である同一生成元ポリシー(Same-Origin Policy)を緩和し、異なるドメイン間でリソースを共有するための仕組みです。

CORSとは

CORSは、「Webページで実行されているスクリプトが、そのページとは異なるオリジン(ドメイン、プロトコル、ポートの組み合わせ)にあるリソースにアクセスすることを許可するための仕組み」です。具体的には、HTTPヘッダーを用いて、サーバー側がどのドメインからのアクセスを許可するかを指定します。

  • Origin : どこドメインからのリクエストなのか指定
  • Access-Conrtol-Allow-Origin : リソースがどのドメインからアクセスできるの指定。「*」の場合、全て許可する

なぜ必要になったのか

Webの初期においては、異なるオリジン間のリソース共有はあまり問題になりませんでした。しかし、Webアプリケーションの高度化に伴い、複数のドメインにまたがるサービスやAPIの利用が増加しました。このような状況で、同一生成元ポリシーが厳格に適用されると、正当なリクエストもブロックされてしまい、Webアプリケーションの利便性が損なわれます。そこで、安全性を確保しつつ異なるオリジン間のリソース共有を可能にするために、CORSが必要となりました。

CORSの歴史

時期 出来事 詳細
1995年 同一生成元ポリシーの導入 Netscape Navigator 2.02でJavaScriptが導入された直後に、悪意のあるWebサイトが他のWebサイトのデータを不正に取得するのを防ぐ目的で導入。
Webアプリ進化後 異なるオリジン間のリソース共有の必要性の高まり Webアプリケーションの高度化に伴い、複数のドメインにまたがるサービスやAPIの利用が増加。同一生成元ポリシーが厳格に適用されると、正当なリクエストもブロックされてしまい、Webアプリケーションの利便性が損なわれる状況が発生。
初期の解決策 JSONP(JSON with Padding)などのハック的な手法 異なるオリジン間のリソース共有を実現するための初期の解決策としてJSONPが用いられた。しかし、JSONPはGETリクエストしか使用できない、エラーハンドリングが難しい、セキュリティ上の脆弱性(例えば、クロスサイトスクリプティング(XSS)攻撃のリスク)があるなどの問題点や制約が存在した。
2000年代後半 W3CによるCORSの標準化 W3C(World Wide Web Consortium)によってCORSの標準化が進められ、HTML5の一部として仕様が定められた。
現在 CORSの普及 CORSの標準化により、より安全で標準的な方法で異なるオリジン間のリソース共有が可能になった。現在のWebアプリケーション開発において、異なるオリジン間のAPI連携などで広く利用されている。

CORSがない場合どうなる

CORSがない場合、同一生成元ポリシーによって、異なるオリジンからのリクエストはブラウザによってブロックされます。例えば、http://example.com のWebページから https://api.example.net のAPIにXMLHttpRequestでリクエストを送信しようとすると、CORSがない場合、ブラウザはリクエストを送信しますが、レスポンスを受け取ってもスクリプトからはアクセスできず、コンソールにエラーを表示します。

エラーメッセージ

No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORSの例

CORSリクエストは、大きく分けて以下の3つのパターンに分類できます

  • プリフライトリクエスト
  • 単純リクエスト
  • 資格情報を含むリクエスト

プリフライトリクエスト

リクエスト初めに`OPTIONメソッドによるHTTPリクエスト(プリフライトリクエスト)を送り、実際のリクエストを送っても安全かを確認します。
リクエストがユーザーデータに影響を与える可能性があるような場合に行われます。

プリフライトリクエストでは「実際のリクエストのメソッド」、「実際のリクエストで送りたいヘッダー」を送信し、
リスポンスでは、「有効なメソッド」、「有効なヘッダー」、「有効なオリジン)」、「有効なキャッシュ時間」を返します。

プリフライトリクエストが完了したら、実際のリクエストを送ります。

# プリフライトリクエストヘッダー
Access-Control-Request-Method: POST // 実際のリクエストのメソッド
Access-Control-Request-Headers: content-type,x-pingother // 実際のリクエストで送りたいヘッダー

3 プリフライトリスポンスヘッダー
Access-Control-Allow-Origin: https://foo.example  // 有効なオリジン
Access-Control-Allow-Methods: POST, GET, OPTIONS  / 有効なメソッド
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type // 有効なヘッダー
Access-Control-Max-Age: 86400 // 有効なキャッシュ時間

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#プリフライトリクエスト

単純リクエスト

以下の条件を満たす場合はプリフライトリクエストが発生しません。
その場合はAccess-Control-Allow-Originヘッダーでのドメインの判定のみ行われます。

単純リクエストの条件

条件 詳細
メソッド GET、HEAD、POST のいずれか
リクエストヘッダー 以下のヘッダー以外を含まないこと(ユーザーエージェントによって自動的に設定されるヘッダーは除く)。
- Accept
- Accept-Language
- Content-Language
- Content-Type
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
Content-Typeヘッダーの値 以下のいずれかであること。
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain

資格情報を含むリクエスト

資格情報を含むリクエストを行う場合、クライアント側でcredentialsオプションをincludeに設定する必要があります。また、サーバー側はプリフライトリクエストと実際のリクエストの両方のレスポンスにAccess-Control-Allow-Credentials: trueを設定する必要があります

const url = "https://bar.other/resources/credentialed-content/";

const request = new Request(url, { credentials: "include" });

const fetchPromise = fetch(request);
fetchPromise.then((response) => console.log(response));
# プリフライトリスポンスヘッダー
Access-Control-Allow-Credentials: true

# リクエストヘッダー
Cookie: pageAccess=2

# リスポンスヘッダー
Access-Control-Allow-Credentials: true

ebi_yuebi_yu

Figma コード生成

ツール名 料金 デザイン再現度 コード生成言語 フレームワーク対応 その他機能
CodeGenerator 無料 React × カスタムプロパティ対応
anima 有料(無料枠あり) React,Vue, HTML/CSS アニメーション、インタラクション
Builder.io 有料(無料枠あり) React, HTML/CSS CMS機能、A/Bテスト
Locofy.ai 有料(無料枠あり) React, HTML/CSS Eコマース機能、SEO最適化
ebi_yuebi_yu

色々触ってみたが微妙。

figmaの画像をスクショ + cluad 3.5で生成が一番良いかも。

ebi_yuebi_yu

BitnamiのKeycloak Dockerイメージへのコンテナアクセス時には非特権ユーザがデフォルトで使われる

BitnamiのKeycloak Dockerイメージ(bitnami/keycloak:24.0.2)では、デフォルトでrootユーザーのパスワードは設定されていません。通常、非特権ユーザー(ID: 1001)が使用されます。

docker execでコンテナにアクセスする際、rootユーザーのパスワードは不要で、以下のコマンドでrootとして入ることができます:

docker exec -it --user root <container_name> bash
ebi_yuebi_yu

Error:caseで元エラーをErrorオブジェクトに含める

  • Errorオブジェクトのcaseに元のエラーを含める
  • ネストされたtry catchでも機能する

コード例

try {
  connectToDatabase();
} catch (err) {
  throw new Error("データベースへの接続に失敗しました。", { cause: err });
}

// 入れ子構造になっていても全てのcaseを保持
try {
  try {
    connectToDatabase();
  } catch (err) {
    throw new Error("データベースへの接続に失敗しました。", { cause: err });
  }
} catch (err) {
  throw new Error("hogeError", { cause: err });
}

throwされるErrorの構造例

{
  name: "Error",
  message: "hogeError",
  cause: {
    name: "Error",
    message: "データベースへの接続に失敗しました。",
    cause: {
      name: "Error",
      message: "オリジナルの接続エラー"
    }
  }
}

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

ebi_yuebi_yu

AIでコード開発からデプロイまでの動化

  1. felo: 要件定義書を作成
  2. v0: UIデザインを作成。
  3. ChatGPT: 画面設計書を作成。
  4. Replit Agent: [設計書、定義書、UIデザインをもとにコード開発を自動化]

参考リンク

https://qiita.com/ryosuke_ohori/items/c40d357bdab6e6cb1c56

https://zenn.dev/masa_oka108/articles/92669dbfc3bfd9

考察

  • 実際のフローはこれだけで完結することが可能なアプリが限定される。
  • コンポーネントのコントロール性やデプロイ対策に不安な点も見られる。
  • コンポーネントの質、安全性、活用性については今後の調査が必要。
ebi_yuebi_yu

pgvector

  • PostgresSQLの拡張機能
  • PostgresSQLをベクトルデータベースとしてとして使うためのもの
  • ベクトルデータの検索方法には以下がある
    • L2 距離(ユークリッド距離)
    • 内積
    • コサイン類似度(またはコサイン距離)

https://github.com/pgvector/pgvector

1. L2距離(ユークリッド距離)

概要:

2つのベクトルの「直線距離」を計算します。ベクトルがどれくらい離れているかを測る指標です。

https://taketake2.com/N102.html

特徴:

  • 距離が小さいほどベクトルが近い(似ている)。
  • スケールの影響を受けやすい(値が大きいと影響が増す)。

2. 内積

概要

2つのベクトルの「方向と大きさ」を掛け合わせた値です。内積が大きいほど、ベクトルが「似た方向」を向いていることを示します。

https://taketake2.com/N43.html

特徴

  • 値が正のとき、2つのベクトルは同じ方向。
  • 値が負のとき、2つのベクトルは反対方向。
  • スケール(ベクトルの長さ)に影響を受ける。

3. コサイン類似度(コサイン距離)

概要

2つのベクトルの「角度」に基づいて類似度を測ります。大きさの影響を受けないため、方向の比較に適しています。

https://taketake2.com/N103.html

特徴

  • 1(完全一致)から-1(完全反対)までの値を取る。
  • ベクトルの大きさ(スケール)の影響を受けない。
  • コサイン類似度が高いほど、2つのベクトルは同じ方向を向いている。

用途

AI用ベクトルデータベースにおける指標選択の基準

AI用のベクトルデータベースを利用する際には、データの特性や目的に応じて適切な指標を選択することが重要です。以下に、各指標を選択する際の基準をまとめます。

1. L2距離

  • 用途: 主にベクトル間の実際の距離を測定するために使用。
  • 基準:
    • ベクトルのスケールが統一されている場合に適しています。
    • 物理的な距離や誤差を評価する際に有効です。
    • スケールの違いが結果に影響を与えない状況で使用。

2. 内積

  • 用途: ベクトルの方向性と大きさを同時に評価。
  • 基準:
    • ベクトルの大きさが結果に重要な影響を与える場合に適しています。
    • 同じ方向を向いているベクトルを強調したい場合に使用。
    • 大きな値が重要な意味を持つ評価に適しています。

3. コサイン類似度

  • 用途: ベクトルの方向性のみを評価。
  • 基準:
    • ベクトルの大きさを無視し、方向性の類似度を重視する場合に適しています。
    • スケールが異なるベクトル間の比較に最適です。
    • ベクトルの角度の一致度を評価したい場合に使用。

選択のポイント

  • データのスケール: データのスケールが異なる場合は、コサイン類似度を選択することでスケールの影響を排除できます。
  • 評価の目的: 距離を測定したいのか、方向性を評価したいのかによって指標を選択します。
  • 計算コスト: 内積やコサイン類似度は計算が比較的軽量であるため、大規模データセットにおいても効率的に使用できます。

これらの基準を考慮し、目的に応じた指標を選択することで、AI用ベクトルデータベースを効果的に活用できます。

参考

https://qiita.com/hmatsu47/items/b393cecef8ed9df57c35#テーブル作成データ投入

https://taketake2.com