目次

Apricot ユーザ認証

y2sunlight 2020-09-03

Apricot ドキュメント に戻る

目次


Apricotでは次の2つのユーザ認証をサポートしています。

セッション認証ではRemember-Meトークンによる自動ログインもサポートしています。

これらのユーザ認証の基盤はApricotコアに含まれています。Apricotのスケルトンではこの基盤を使って認証用のミドルウェアとコントローラーを実装しています。本章では、スケルトンでの認証に関する設定方法を示し、セッション認証用のミドルウェアとコントローラーの作成方法を説明します。


ユーザ認証の設定

認証方法の設定

スケルトンでは、ユーザ認証用のミドルウェアとして、基本認証とセッション認証の2つが用意されています。ミドルウェアの設定は、アプリケーションの設定ファイル app.php で行います。初期設定では、ユーザ認証にはセッション認証が使用されています。

/your-project/config

app.php
<?php
return
[
    // ...
    'middleware' =>[
        \App\Middleware\Auth\SessionAuth::class, /* Session authentication */
    ],
    // ...
];

ユーザ認証を基本認証に変更する場合は、ミドルウェアを以下のように変更して下さい。

app.php
    'middleware' =>[
        \App\Middleware\Auth\BasicAuth::class,   /* Basic authentication */
    ],

基本認証はWebサーバの機能を使ったログインページを作る必要のない認証方法です。比較的小規模で簡易的なアプリケーションの場合に選択することができます。


ユーザ認証の設定

ユーザ認証の設定は、アプリケーションの設定ファイル(app.php)内の auth 要素で行います。

/your-project/config

app.php
<?php
return
[
    // ...
 
    'auth' =>[
        'db'=>[
            'user'=>[
                'account' =>'account',
                'password' =>'password',
                'remember' =>'remember_token',
            ],
        ],
        'expires_sec'=> 2*7*24*3600, /* 2weekws */
        'menu'=> true,
    ],
];

auth.db 要素には以下のデータベースの設定を行います。

上の例では、user テーブルの accountpassword カラムを使ってユーザ認証しています。また、RememberMeトークン保存用のカラムは remember です。必要に応じてテーブル名及びカラム名は変更できます。ここで指定したテーブル名が認証用のユーザモデルになります。

その他に以下のがあります。


認証用のユーザモデルの作成

ユーザ認証の設定には、Authenticatable インターフェースを実装したユーザモデルを作る事が必要です。このモデルのデータベース情報を、前項で説明した app.phpauth.db 要素 に設定して下さい。Apricotのスケルトンでは認証用のユーザモデルとして User クラスを作っています。

/your-project/config

User.php
namespace App\Models;
 
use App\Foundation\Model;
use ORM;
use Apricot\Foundation\Security\Authenticatable;
use App\Foundation\Security\AuthTrait;
 
/**
 * User Model
 */
class User extends Model implements Authenticatable
{
    /**
     * Includeing default implementation of Authenticatable interface.
     */
    use AuthTrait;
 
    // ...    
}

AuthTrait には Authenticatable インターフェースが実装されています( 実際に app.phpauth.db 要素 を使っているのは AuthTrait です)。 従って、AuthTraituse するだけで、それ以上のコーディングは不要です。


AuthUserクラス

AuthUserクラスは、Apricot コアの Authentication クラスをシングルトンにしたもので、全てのユーザ認証機能のこのクラスに集約されています。

AuthUserクラスでは以下のメソッドが使用できます。これらのメソッドは、主にミドルウェアと認証コントローラによって使用されますが、getUser()メソッドは様々な所から呼び出される可能性があります。

使用法: AuthUser::{メソッド}

メソッド機能
authenticate
(string $account, string $password,
bool $remenber=false):bool
ユーザの認証を行い、成功の場合trueを返します。
(アカウントとパスワードで認証します)
remember():boolユーザの自動認証を行い、成功の場合trueを返します。
(RememberMeトークンによる自動ログインで使用します)
check():boolユーザが認証されているか否かを返します。
verify():boolユーザが認証されているか否かを返します。
認証されている場合、ログインユーザ情報の更新を行います。
forget()ログインセッションを削除します。
getUser():objectログインユーザを返します。
getPathAfterLogin():stringログイン後のURLパスを返します。


AuthUserクラスの実装

Apricotのスケルトンでは、以下のように AuthUser クラスが実装されています。

/your-project/app/Foundation/Security

AuthUser.php
<?php
namespace App\Foundation\Security;
 
use Core\Foundation\Singleton;
use Core\Foundation\Security\Authentication;
use App\Models\User;
 
class AuthUser extends Singleton
{
    /**
     * Create user authentication instance.
     * @return \Core\Foundation\Security\Authentication
     */
    protected static function createInstance()
    {
        return new Authentication(new User());
    }
}

createInstance() では、ユーザモデル( User )を使って、Authentication クラスのシングルトンを生成しています。同様の方法で別のユーザモデルを使用した Authentication クラスのシングルトンも同時に作る事ができます。例えば、Userとは別に、AdminUser クラスや ApiUser クラスを使用した認証などが考えられます。

このように、Apricotのスケルトンでは潜在的にマルチ認証を想定した実装ができるように配慮しています。但し、マルチ認証を行う場合は、ミドルウェアと認証コントローラを追加またはカスタマイズする必要があります。


ミドルウェア

セッション認証

セッション認証のミドルウェアは、/App/Middleware/Auth/SessionAuth です。他のミドルウェアと同様に、middlewareインターフェースの process() メソッドを実装し、その中で認証処理を行っています。

以下に、SessionAuth ミドルウェアがどのようにAuthUserクラスを使って認証処理を実行しているのかについて説明します。

/your-project/app/Middleware/Auth

SessionAuth.php
/**
 * Middleware - Session authentication
 */
class SessionAuth implements Middleware
{
    /**
     * @var array List of controllers to exclude
     */
    private $exclude = [
        'AuthController',
    ];
 
    /**
     * {@inheritDoc}
     * @see \Apricot\Foundation\Middleware\Middleware::invoke()
     */
    public function process(Invoker $next): Response
    {
        // When excluded controller.
        if (in_array(controllerName(), $this->exclude))
        {
            return $next->invoke();
        }
 
        // Verifys whether user is authenticated.
        if (AuthUser::verify())
        {
            return $next->invoke();
        }
 
        // Redirect to login page If not authenticated.
        return redirect(route('login'));
    }
}

$this->exclude 配列に含まれているコントローラは認証から除外します。通常は、ここには認証コントローラ( 上例では AuthController )が含まれます。他には、公開のページやWebAPIなどが含まれます。

AuthUser::verify() でユーザが認証されているか否かを調べ、認証されていれば次の処理に制御を渡します。まだユーザ認証されていない場合は、ヘルパー関数 redirect() を呼び出してログインページ画面にリダイレクトします。

ミドルウェアでは、認証のチェックに AuthUser::check()ではなくて、AuthUser::verify() を使用するのは、後者のメソッドがログインユーザ情報の更新を行うからです。これによって AuthUser は常に最新のログインユーザ情報を保持することができます。


基本認証

基本認証のミドルウェアは、/App/Middleware/Auth/BasicAuth です。このクラスは以下に配置されていますので、必要に応じて参照して下さい。

/your-project/app/Middleware/Auth/BasicAuth.php


認証コントローラ

セッション認証を使用した場合の認証コントローラについて説明します。Airpcotのスケルトンでは、認証コントローラとして App\Controllers\AuthController を提供しています。

ルーティング

AuthControllerルーティングは以下のように定義されています。

/your-project/config

routes.php
$r->get ('/login', 'AuthController@showForm');
$r->post('/login', 'AuthController@login');
$r->get ('/logout', 'AuthController@logout');


AuthControllerクラス

セッション認証ではログインページから入力されるユーザアカウントとパスワードでユーザを認証します。また、ログイン時に、ブラウザ終了後もログイン状態を保持するか否かのチェック( Remember-Me )を行うことができます。

これらの処理は、AuthController クラスによって実行されます。以下に、このクラスのアクションがどのようにAuthUserクラスを使ってどのように認証処理を実行しているのかについて説明します。

showFormアクション

public function showForm()
{
    if (AuthUser::check())
    {
        // Redirects to the top page if authenticated
        return redirect(route(''));
    }
 
    if (AuthUser::remember())
    {
        // Redirects to the top page display if automatic authentication is possible
        return redirect(route(''));
    }
 
    return render('login');
}

AuthUser::check() でユーザが認証されているか否かのチェックを行い、成功の場合は、ヘルパー関数 redirect() でトップ画面にリダイレクトします。

一方、AuthUser::check()が失敗した場合は、AuthUser::remember() で自動ログインを試みます。これが成功した場合は、トップ画面にリダイレクトします。

ユーザセッションもなく、自動ログインにも失敗した場合、コントローラーはログインページをレンダリングします。


loginアクション

public function login()
{
    $inputs = Input::all();
 
    if (!AuthUser::authenticate($inputs['account'], $inputs['password'], !empty($inputs['remember'])))
    {
        // If the user cannot be found
        $errorBag = new ErrorBag([__('auth.login.error.no_account')]);
        return redirect(back())->withInputs()->withErrors($errorBag);
    }
 
    // When login is successful
    return redirect(AuthUser::getPathAfterLogin());
}
TODO:

まず、Input::all()でログインページから入力変数を取得します。そして、それらの変数をパラメータにして AuthUser::authenticate() でユーザ認証を行います。認証に成功した場合、AuthUser::getPathAfterLogin() でログイン後のに遷移するページのパスを取得して、そこにリダイレクトします。

認証に失敗した場合は、withInputs()で入力変数を、withErrors()でバリデーションのエラーバッグを、それぞれのフラッシュ変数に保存し、ログインページにリダイレクトします。


logoutアクション

public function logout()
{
    // Destroys the session
    AuthUser::forget();
 
    // Redirects to the login page
    return redirect(route("login"));
}

AuthUser::forget() で認証セッションを破棄し、ログインページにリダイレクトします。


コアのユーザ認証機能

Apricotのコアで提供するユーザ認証機能を以下に示します。これらは、アプリケーションのモデルやデータベースに依存しない基本的なもので、ミドルウェアや認証コントローラーなどで使用されます。


Authenticatableインターフェース

Apricotコアのユーザ認証機能を使用するには、Authenticatable インターフェースを実装したモデルを作成する必要があります。

完全修飾名 : Apricot\Foundation\Security\Authenticatable

メソッド機能
getAuthName():string認証を識別できる任意の名前を返します。
通常は認証のモデルとなるテーブル名を返します。(例:user)
authenticateUser
(string $account, string $password)
:object|bool
ユーザの認証を行います。
成功の場合ユーザオブジェクトを返し、他は false を返します。
(通常はアカウントとパスワードによる認証を行います)
remember
(string $remenber_token)
:object|bool
ユーザのRemnber-Meトークンによる認証を行います。
成功の場合ユーザオブジェクトを返し、他は false を返します。
(RememberMeトークンによる自動ログインで使用します)
retrieveUser(object $user)
:object|bool
ユーザオブジェクトの再検索を行います。
成功の場合ユーザオブジェクトを返し、他は false を返します。
再検索のキーは引数 $user のアカウントが使えます。
saveRemenberToken
(object $user, string $remenber_token)
:bool
ユーザのRemnber-Meトークンを保存します。
保存時のキーは引数 $user のアカウントが使えます。

Apricotのスケルトンでは、Authenticatable インターフェースを実装した AuthTrait を使用することができるので、そちらを利用して下さい:

/your-project/app/Foundation/Security/AuthTrait.php


Authenticationクラス

Authenticationクラスはユーザ認証を行う全ての機能を持っています。通常、このクラスは、ミドルウェアと認証コントローラで使用されます。

完全修飾名 : Apricot\Foundation\Security\Authentication

メソッド機能
__construct
(Authenticatable $auth)
Authenticationのコンストラクタ
生成時にAuthenticatableインターフェースを与えます。
authenticate
(string $account, string $password,
bool $remenber=false):bool
ユーザの認証を行い、成功の場合trueを返します。
(アカウントとパスワードで認証します)
remember():boolユーザの自動認証を行い、成功の場合trueを返します。
(RememberMeトークンによる自動ログインで使用します)
check():boolユーザが認証されているか否かを返します。
verify():boolユーザが認証されているか否かを返します。
認証されている場合、ログインユーザ情報の更新を行います。
forget()ログインセッションを削除します。
getUser():objectログインユーザを返します。
getPathAfterLogin():stringログイン後のURLパスを返します。

本クラスは基本的にセッション認証用に作られていますが、基本認証の場合も authenticate()、verify()、getUser()メソッドは使用できます(基本認証の認証ページはブラウザによって提供され、ログアウトという考え方はなく、セッションとログイン状態は常に一致します)。また、check() と verify() は似たようなメソッドですが、check()はコントローラのアクションで、verify()はミドルウェアでの使用を想定しています。