認証機能

Authenticatorは、リクエストを認証操作に変換する処理を行います。 それらは、 Identifiers を利用して、既知の Identity Objects を見つけます。

Session

この認証機能は、セッションにユーザー情報や資格情報が含まれているかどうかをチェックします。 以下に挙げた Form のようなステートフルな認証機能を使う場合、 ユーザーが一度ログインしたら、それ以降でセッションからデータを取得されるように、 最初に Session の認証機能をロードするようにしてください。 設定オプション:

  • sessionKey: ユーザーのセッションキー, デフォルトは Auth

  • identify: bool true の値を指定してこのキーを設定すると、 セッションの認証情報を識別子と照合できるようになります。 true の場合、設定された Identifiers はリクエストのたびにセッションに 保存されたデータを使ってユーザを識別するために使われます。デフォルト値は false.

  • fields: username フィールドをユーザストレージ内の一意の識別しに写像することができます。 デフォルトは username です。 このオプションは identify オプションが true に設定されている場合に使用されます.

Form

リクエストボディのデータを調べます。通常、フォームの送信が POST / PUT 経由で行われる場合が多いです。

設定オプション:

  • loginUrl: ログインURL、文字列またはURLの配列。デフォルトは``null`` で、すべてのページがチェックされます。

  • fields: usernamepassword を指定したPOSTフィールドに描画する配列です。

  • urlChecker: URLチェッカーのクラスまたはオブジェクト。デフォルトは DefaultUrlChecker

  • useRegex: URLのマッチングに正規表現を使うかどうか。 デフォルトは false.

  • checkFullUrl: クエリ文字を含むURLをチェックするかどうか。 ログインフォームが別のサブドメインにある場合に便利です。 デフォルトは、false

警告

URLに配列構文を使用した場合、URLはCakePHPルータによって生成されます。 結果は、ルート処理によってはリクエストURIに実際にあるものと 異なる かもしれない。 大文字小文字を区別するために、これを考慮してください

トークン

トークン認証機能は、ヘッダーやリクエストパラメータの中にある リクエストと一緒に来るトークンに基づいてリクエストを認証することができます。

設定オプション:

  • queryParam: クエリパラメータの名前. クエリパラメータからトークンを取得したい場合に設定します。

  • header: ヘッダーの名前. ヘッダーからトークンを取得したい場合に設定します。

  • tokenPrefix: オプションのトークンプレフィックス。

ヘッダやクエリ文字列からトークンを取得する例は次のようになります:

$service->loadAuthenticator('Authentication.Token', [
    'queryParam' => 'token',
    'header' => 'Authorization',
    'tokenPrefix' => 'Token'
]);

上記の場合、 Token の前にトークンとスペースがある限り、 token のGETパラメータまたは Authorization ヘッダが読み込まれます。

トークンは常に次のように設定された識別子に渡されます:

[
    'token' => '{token-value}',
]

JWT

JWT 認証機能は、ヘッダーまたはクエリパラメータから JWT token を取得し、 ペイロードを直接返すか、識別子に渡して別のデータソースなどと照合して検証します。

  • header: トークンを確認するためのヘッダー行です。デフォルトは Authorization です。

  • queryParam: トークンをチェックするクエリパラメータ。デフォルトは token です。

  • tokenPrefix: prefixトークン. デフォルトは bearer です。

  • algorithm: Firebase JWT のハッシュアルゴリズム。デフォルトは 'HS256' です。

  • returnPayload: 識別子を経由せずに、トークンのペイロードを直接返すか返さないか。デフォルトは true です。

  • secretKey: デフォルトは null ですが、秘密鍵を Security::salt() 提供しているCakePHPアプリケーションのコンテキストではない場合は 必須 です。

デフォルトでは、 JwtAuthenticator は対称鍵アルゴリズム HS256 を使用し、暗号化鍵として、 Cake\Utility\Security::salt() の値を使用します。:

# 秘密鍵生成
openssl genrsa -out config/jwt.key 1024
# 公開鍵生成
openssl rsa -in config/jwt.key -outform PEM -pubout -out config/jwt.pem

jwt.key ファイルは秘密鍵であり、安全に保管する必要があります。 jwt.pem ファイルは公開鍵です。 このファイルは、モバイルアプリなどの外部アプリケーションによって作成されたトークンを 検証する必要がある場合に使用する必要があります。

以下の例では、 JwtSubject 識別しを用いてトークンの sub (subject) に基づいてユーザーを識別し、 トークンの検証に公開鍵を使用するように、 Authenticator を設定しています。

Application クラスに以下を追加してください:

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
    $service = new AuthenticationService();
    // ...
    $service->loadIdentifier('Authentication.JwtSubject');
    $service->loadAuthenticator('Authentication.Jwt', [
        'secretKey' => file_get_contents(CONFIG . '/jwt.pem'),
        'algorithm' => 'RS256',
        'returnPayload' => false
    ]);
}

UsersController に追加:

public function login()
{
    $result = $this->Authentication->getResult();
    if ($result->isValid()) {
        $privateKey = file_get_contents(CONFIG . '/jwt.key');
        $user = $result->getData();
        $payload = [
            'iss' => 'myapp',
            'sub' => $user->id,
            'exp' => time() + 60,
        ];
        $json = [
            'token' => JWT::encode($payload, $privateKey, 'RS256'),
        ];
    } else {
        $this->response = $this->response->withStatus(401);
        $json = [];
    }
    $this->set(compact('json'));
    $this->viewBuilder()->setOption('serialize', 'json');
}

公開鍵ファイルを外部アプリに共有する以外にも、 以下のようにアプリを設定することで、 JWKSのエンドポイントを経由して公開鍵ファイルを配布することができます。:

// config/routes.php
$builder->setExtensions('json');
$builder->connect('/.well-known/:controller/*', [
    'action' => 'index',
], [
    'controller' => '(jwks)',
]); // connect /.well-known/jwks.json to JwksController

// controller/JwksController.php
public function index()
{
    $pubKey = file_get_contents(CONFIG . './jwt.pem');
    $res = openssl_pkey_get_public($pubKey);
    $detail = openssl_pkey_get_details($res);
    $key = [
        'kty' => 'RSA',
        'alg' => 'RS256',
        'use' => 'sig',
        'e' => JWT::urlsafeB64Encode($detail['rsa']['e']),
        'n' => JWT::urlsafeB64Encode($detail['rsa']['n']),
    ];
    $keys['keys'][] = $key;

    $this->viewBuilder()->setClassName('Json');
    $this->set(compact('keys'));
    $this->viewBuilder()->setOption('serialize', 'keys');
}

JWKSの詳細情報は https://datatracker.ietf.org/doc/html/rfc7517 または https://auth0.com/docs/tokens/json-web-tokens/json-web-key-sets を参照してください。

Http基本

https://en.wikipedia.org/wiki/Basic_access_authentication を確認してください。

設定オプション:

  • realm: デフォルトは $_SERVER['SERVER_NAME'] で、必要に応じて上書きしてください。

Httpダイジェスト

https://en.wikipedia.org/wiki/Digest_access_authentication を確認してください。

設定オプション:

  • realm: デフォルトは null です。

  • qop: デフォルトは auth です。

  • nonce: デフォルトは uniqid(''), です。

  • opaque: デフォルトは null です。

クッキー認証機能 別名 "Remember Me"

クッキー認証機能を使用すると、ログインフォームに "remember me" 機能を実装することができます。

ログインフォームに、この認証機能で設定されているフィールド名と一致するフィールドがあることを確認してください。

クッキーを暗号化して複合化するには、AuthenticationMiddlewareの 前に EncryptedCookieMiddlewareをアプリに追加したことを確認してください。

設定オプション:

  • rememberMeField: デフォルトは remember_me です。

  • cookie: クッキーオプションの配列:

    • name: クッキー名, デフォルトは CookieAuth

    • expire: 有効期限, デフォルトは null です。

    • path: パス, デフォルトは / です。

    • domain: ドメイン, デフォルトは空の文字列です ``

    • secure: Bool, デフォルトは false です。

    • httpOnly: Bool, デフォルトは false です。

    • value: Value, デフォルトは空の文字列です。 ``

  • fields: usernamepassword を指定されたIDフィールドにマップする配列

  • urlChecker: URLチェッカーのクラスまたはオブジェクト。デフォルトは DefaultUrlChecker

  • loginUrl: ログイン URL, 文字列または URL の配列。 デフォルトは null で、すべてのページがチェックされます。

  • passwordHasher: トークンハッシュに使うパスワードハッシャー。デフォルトは DefaultPasswordHasher::class.

OAuth

現在のところ、OAuth認証機能の実装予定はありません。 その主な理由は、OAuth 2.0が認証プロトコルではないからです。

このトピックについて知りたい場合は、 ここ.

将来的にはOpenID Connect認証機能を追加するかもしれません。

イベント

認証によって発生するイベントは1つだけです。: Authentication.afterIdentify.

イベントとは何か、イベントの使い方がわからない場合は ここをクリックしてください!.

身元の特定に成功した後に Authentication.afterIdentify イベントが AuthenticationComponent によって発行されます。

イベントには以下のデータが含まれています。:

  • provider: \Authentication\Authenticator\AuthenticatorInterface を実装したオブジェクトです。

  • identity: \ArrayAccess を実装したオブジェクトです。

  • service: \Authentication\AuthenticationServiceInterface を実装したオブジェクトです。

イベントのサブジェクトは、AuthenticationComponent がアタッチされている 現在のコントローラのインスタンスになります。

しかし、このイベントが発生するのは、IDを識別するために使用された authenticator が永続的ではなく、ステートレスではない場合に限られます。 これは、例えばセッション認証やトークンがリクエストのたびに毎回イベントを発生させてしまうからです。

含まれている認証子からは、FormAuthenticatorのみがイベントを発生させます。 その後、セッション認証機能がIDを提供します。

URL チェッカー

FormCookie のような認証証は、 /login ページのような 特定のページでのみ実行されるべきものがあります。 これは、URLチェッカーを使用することで実現できます。

デフォルトは DefaultUrlChecker を使います。 これは、正規表現チェックをサポートした文字列URLを比較に使用します。

設定オプション:

  • useRegex: URLのマッチングに正規表現を使用するかどうか。デフォルトは false です。

  • checkFullUrl: フルURLをチェックするかどうか。 ログインフォームが別のサブドメインにある場合に便利です。 デフォルトは false です。

フレームワーク固有の URL のサポートが必要な場合など、カスタム URL チェッカーを実装することができます。 この場合は Authentication\UrlChecker\UrlCheckerInterface を実装してください。

もっと詳しくURLチェッカーについて知るには このページを見てください.

成功した Authenticator または Identifier の取得

ユーザーの認証が完了した後、ユーザーの認証に成功した Authenticator を確認したり、 次のような操作を行うことができます。:

// コントローラー、アクションの中
$service = $this->request->getAttribute('authentication');

// 認証に失敗した場合、または認証機能がある場合は null になります。
$authenticator = $service->getAuthenticationProvider();

ユーザーを特定した識別子も取得できます。:

// コントローラー、アクションの中
$service = $this->request->getAttribute('authentication');

//  認証に失敗した場合は null になります。
$identifier = $service->getIdentificationProvider();

ステートフル認証でステートレス認証を使用する

TokenHttpBasic を使用している場合は、他の認証しと一緒に HttpDigest を使用します。 これらの認証子は、認証証明書が見つからないか無効な場合にリクエストを停止することを覚えておくべきです。 これは、これらの認証子がレスポンスの中で特定のチャレンジヘッダを送信しなければならないために必要です:

use Authentication\AuthenticationService;

// サービスのインスタンス化
$service = new AuthenticationService();

// 識別子の読み込み
$service->loadIdentifier('Authentication.Password', [
    'fields' => [
        'username' => 'email',
        'password' => 'password'
    ]
]);
$service->loadIdentifier('Authentication.Token');

// Basicを最後にして、認証子をロードします。
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form');
$service->loadAuthenticator('Authentication.HttpBasic');

もし HttpBasicHttpDigest と他の認証子を組み合わせたい場合は、 これらの認証子はリクエストを中止してブラウザのダイアログを強制的に表示するので注意してください。

認証されていないエラーの処理

認証されていないユーザがいた場合、 AuthenticationComponent は例外を発生させます。 この例外をリダイレクトに変換するには AuthenticationService を設定する際に unauthenticatedRedirect を使ってください。

また、 queryParam オプションを使って現在のリクエストのターゲットURIを クエリパラメータとして渡すこともできます:

// src/Application.phpのgetAuthenticationService() メソッドの中

$service = new AuthenticationService();

// 認証されていないときにリダイレクトする
$service->setConfig([
    'unauthenticatedRedirect' => '/users/login',
    'queryParam' => 'redirect',
]);

そして、コントローラのログインメソッドの中で``getLoginRedirect()`` を使うことで、クエリ文字列パラメータ:からリダイレクト先を安全に取得することができます。:

public function login()
{
    $result = $this->Authentication->getResult();

    // Regardless of POST or GET, redirect if user is logged in
    if ($result->isValid()) {
        // Use the redirect parameter if present.
        $target = $this->Authentication->getLoginRedirect();
        if (!$target) {
            $target = ['controller' => 'Pages', 'action' => 'display', 'home'];
        }
        return $this->redirect($target);
    }
}