学びメモ 2025/01
後で読む
やること
- qiita記事とzeen記事のgithub連携
keycloak SPI
- Service Provider Interface
- keycloakの機能を拡張したい/カスタム機能を作りたい時に使用する
- SPI実装には
Provider
とProviderFactory
を実装する必要がある
1. Provider インターフェース
実際の機能やロジックを提供するクラスの基盤となるインターフェース。
2. ProviderFactory インターフェース
Provider を生成および管理するための工場 (Factory) クラスの基盤となるインターフェース。
Authenticator SPI
Keycloakの認証フローの動作をカスタマイズするためのSPI
Authenticator SPIの構成
認証SPIを実装するには、以下のインターフェイスやクラスを実装します。
-
Authenticator
: 認証ロジックの実装。 -
AuthenticatorFactory
: 認証器を生成するファクトリクラス。 -
ProviderConfigProperty
: 設定項目を定義。 -
KeycloakSession
とAuthenticationFlowContext
: 認証のために必要な状態やセッション情報の管理。
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
KeycloakSession
と AuthenticationFlowContext
の使用
-
KeycloakSession は、ユーザーやセッション情報を操作するために使用します。
MyAuthenticator
のauthenticate()
メソッド内でセッション情報にアクセスすることができます。 -
AuthenticationFlowContext は、現在の認証フローの状態を保持し、認証結果やエラーを通知します。例えば、
context.success()
やcontext.failure()
を呼び出すことで、認証の結果を反映します。
mvn install
コマンドとローカルリポジトリについて
Mavenの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
はプロジェクトをビルドし、生成されたアーティファクトをローカルリポジトリにインストールします。 - 依存関係がリモートリポジトリからローカルリポジトリにダウンロードされ、キャッシュされます。
- インストールされたアーティファクトは、他のプロジェクトでも再利用可能です。
Cannot access '******' before initialization
回避
Jest.mockでのエラー原因と解決方法
-
エラー原因
初期化前のtestToken
を参照してしまう。 -
解決方法
遅延評価を利用し、以下のように修正する。
jest.mock('jwt-decode', () => {
return {
// ダメな例 : jwtDecode: jest.fn().mockReturnValue(tetstToken)
jwtDecode: jest.fn(() => testToken), // 呼び出し時に testToken を評価
};
});
-
ポイント
-
mockReturnValue
は即時評価。 -
jest.fn(() => testToken)
は関数実行時に評価されるため、初期化順序の問題を回避できる。
-
フロントエンド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: *
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 // 有効なキャッシュ時間
単純リクエスト
以下の条件を満たす場合はプリフライトリクエストが発生しません。
その場合は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
Figma コード生成
ツール名 | 料金 | デザイン再現度 | コード生成言語 | フレームワーク対応 | その他機能 |
---|---|---|---|---|---|
CodeGenerator | 無料 | △ | React | × | カスタムプロパティ対応 |
anima | 有料(無料枠あり) | ◎ | React,Vue, HTML/CSS | ◯ | アニメーション、インタラクション |
Builder.io | 有料(無料枠あり) | ◯ | React, HTML/CSS | ◯ | CMS機能、A/Bテスト |
Locofy.ai | 有料(無料枠あり) | ◯ | React, HTML/CSS | ◯ | Eコマース機能、SEO最適化 |
色々触ってみたが微妙。
figmaの画像をスクショ + cluad 3.5で生成が一番良いかも。
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
Bitnami
- ウェブアプリケーションとMySQLなどのミドルウェアをまとめてパッケージングしてくれる
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: "オリジナルの接続エラー"
}
}
}
AIでコード開発からデプロイまでの動化
- felo: 要件定義書を作成
- v0: UIデザインを作成。
- ChatGPT: 画面設計書を作成。
- Replit Agent: [設計書、定義書、UIデザインをもとにコード開発を自動化]
参考リンク
考察
- 実際のフローはこれだけで完結することが可能なアプリが限定される。
- コンポーネントのコントロール性やデプロイ対策に不安な点も見られる。
- コンポーネントの質、安全性、活用性については今後の調査が必要。
pgvector
- PostgresSQLの拡張機能
- PostgresSQLをベクトルデータベースとしてとして使うためのもの
- ベクトルデータの検索方法には以下がある
- L2 距離(ユークリッド距離)
- 内積
- コサイン類似度(またはコサイン距離)
1. L2距離(ユークリッド距離)
概要:
2つのベクトルの「直線距離」を計算します。ベクトルがどれくらい離れているかを測る指標です。
特徴:
- 距離が小さいほどベクトルが近い(似ている)。
- スケールの影響を受けやすい(値が大きいと影響が増す)。
2. 内積
概要
2つのベクトルの「方向と大きさ」を掛け合わせた値です。内積が大きいほど、ベクトルが「似た方向」を向いていることを示します。
特徴
- 値が正のとき、2つのベクトルは同じ方向。
- 値が負のとき、2つのベクトルは反対方向。
- スケール(ベクトルの長さ)に影響を受ける。
3. コサイン類似度(コサイン距離)
概要
2つのベクトルの「角度」に基づいて類似度を測ります。大きさの影響を受けないため、方向の比較に適しています。
特徴
- 1(完全一致)から-1(完全反対)までの値を取る。
- ベクトルの大きさ(スケール)の影響を受けない。
- コサイン類似度が高いほど、2つのベクトルは同じ方向を向いている。
用途
AI用ベクトルデータベースにおける指標選択の基準
AI用のベクトルデータベースを利用する際には、データの特性や目的に応じて適切な指標を選択することが重要です。以下に、各指標を選択する際の基準をまとめます。
1. L2距離
- 用途: 主にベクトル間の実際の距離を測定するために使用。
-
基準:
- ベクトルのスケールが統一されている場合に適しています。
- 物理的な距離や誤差を評価する際に有効です。
- スケールの違いが結果に影響を与えない状況で使用。
2. 内積
- 用途: ベクトルの方向性と大きさを同時に評価。
-
基準:
- ベクトルの大きさが結果に重要な影響を与える場合に適しています。
- 同じ方向を向いているベクトルを強調したい場合に使用。
- 大きな値が重要な意味を持つ評価に適しています。
3. コサイン類似度
- 用途: ベクトルの方向性のみを評価。
-
基準:
- ベクトルの大きさを無視し、方向性の類似度を重視する場合に適しています。
- スケールが異なるベクトル間の比較に最適です。
- ベクトルの角度の一致度を評価したい場合に使用。
選択のポイント
- データのスケール: データのスケールが異なる場合は、コサイン類似度を選択することでスケールの影響を排除できます。
- 評価の目的: 距離を測定したいのか、方向性を評価したいのかによって指標を選択します。
- 計算コスト: 内積やコサイン類似度は計算が比較的軽量であるため、大規模データセットにおいても効率的に使用できます。
これらの基準を考慮し、目的に応じた指標を選択することで、AI用ベクトルデータベースを効果的に活用できます。
参考