====== Apricot セッション認証 ====== --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-05-15// [[apricot:top|Apricot に戻る]] 関連記事 * [[apricot:configuration|Apricot プロジェクトの作成]] * [[apricot:public|Apricot 公開フォルダ]] * [[apricot:core:top|Apricot コア]] * [[apricot:app:top|Apricot アプリ]] * Apricot 拡張 * [[apricot:ext:middleware|Apricot ミドルウェア]] * [[apricot:ext:access-log|Apricot アクセスログ]] * [[apricot:ext:csrf|Apricot CSRF対策]] * [[apricot:ext:user-auth|Apricot ユーザ認証]] * [[apricot:ext:basic-auth|Apricot 基本認証]] * Apricot セッション認証 * [[apricot:ext:interceptor|Apricot インターセプター]] * [[apricot:ext:di-container|Apricot DIコンテナー]] ミドルウェアを使ってユーザのセッション認証を実装します。本章ではApricotのユーザ認証機能を使用しているので、まだお読みでない方は先に[[Apricot:ext:user-auth|そちら]]をご一読下さい。 セッション認証ではログイン画面を作成してユーザ認証を行います。この認証方法ではログアウト機能が有効で、Remember-Meトークンによる自動ログイン機能も実装します。比較的多くのユーザでサイトを運用する場合はこの認証方法をお薦めします。 本機能は次の2つの部分に分かれます。 * ミドルウェア --- ユーザ認証状態を検証して、未認証の場合はログイン画面にリダイレクトする * 認証コントローラー --- ログイン画面の表示及びユーザ認証とログインセッションの作成を行う ---- ===== ミドルウェア ===== ==== SessionAuth クラス ==== 以下に、セッション認証のミドルウェアを示します。 {{fa>folder-open-o}} ** /apricot/app/Middleware/Auth ** exclude)) { return $next->invoke(); } // Verify whether user is authenticated if (AuthUser::verify()) { return $next->invoke(); } // 未認証の場合は、ログイン画面を表示 return redirect(route('login')); } } * [[apricot:ext:middleware#Middleware インターフェース|Middleware インターフェース]]の process() メソッドを実装します。 * $this->exclude 配列に含まれているコントローラは認証から除外します。(公開のWebAPIなど) * AuthUser::verify() で既に認証されているかを調べ、認証されていれば次の処理に制御を渡します。 * まだユーザ認証されていない場合は、ヘルパー関数 redirect() を呼び出してログイン画面にリダイレクトします。 AuthUser の使用方法については、[[apricot:ext:user-auth#authuserクラス|こちら]]をご覧ください。 \\ ==== セッション認証の設定 ==== セッション認証のミドルウェアをアプリケーションに設置します。 {{fa>folder-open-o}} ** /apricot/config** 'setup' =>[ ... ], 'middleware' =>[ \App\Middleware\AccessLog::class, /* Access log */ \App\Middleware\VerifyCsrfToken::class, /* Verify CSRF Token */ // \App\Middleware\Auth\BasicAuth::class, /* Basic Auth. */ \App\Middleware\Auth\SessionAuth::class, /* Session Auth. */ ], 'csrf' =>[ ... ], 'auth' =>[ 'db'=>[ 'user'=>[ 'account' =>'account', 'password' =>'password', 'remember' =>'remember_token', ], ], 'expires_sec'=> 2*7*24*3600, /* 2weekws */ 'menu'=> true, ], ]; * 基本認証のミドルウェア(\App\Middleware\Auth\BasicAuth::class)は削除して下さい。 * middleware にセッション認証のミドルウェア \App\Middleware\Auth\SessionAuth::class を追加します。 * auth.expires_sec --- RememberMeトークンクッキーの保存期間(秒単位) * menu --- 画面の左上にユーザメニューを表示するか否か(既定値:false) \\ ===== 認証コントローラ ===== ==== ルーティング ==== 以下のように config/routes.php を変更し、認証コントローラのルートを作ります。 {{fa>folder-open-o}} ** /apricot/config ** //------------------------------------------------------------------- // Route Definition Callback //------------------------------------------------------------------- return function (FastRoute\RouteCollector $r) { $base = Core\Application::getInstance()->getRouteBase(); $r->addGroup($base, function (FastRoute\RouteCollector $r) use($base) { // Auth $r->get ('/login', 'AuthController@showForm'); $r->post('/login', 'AuthController@login'); $r->get ('/logout', 'AuthController@logout'); // User // ... }); }; * /login (GET) --- ログインフォーム表示 * /login (POST) --- ログイン(ユーザ認証) * /logout --- ログアウト \\ ==== AuthController クラス ==== 以下に認証コントローラを示します。 {{fa>folder-open-o}} ** /apricot/app/Controllers ** validate(); if ($response instanceof \Core\Foundation\Response) { return $response; } $inputs = Input::all(); if (!AuthUser::authenticate($inputs['account'], $inputs['password'], !empty($inputs['remember']))) { // ユーザが見つからない $errorBag = new ErrorBag([__('auth.login.error.no_account')]); return redirect(back())->withInputs()->withErrors($errorBag); } // ログイン成功 return redirect(AuthUser::getPathAfterLogin()); } /** * バリデーション * @return void|\Core\Foundation\Response return Response if failed */ private function validate() { $inputs = Input::all(); // Validation $v =(new \Valitron\Validator($inputs)) ->rule('required', 'account') ->rule('alphaNum','account') ->rule('ascii','password') ->labels(inputLabels('auth.login')); if(!$v->validate()) { $errorBag = new ValidatorErrorBag($v->errors()); return redirect(back())->withInputs()->withErrors($errorBag); } } /** * ログアウト * @return \Core\Foundation\Response */ public function logout() { // セッションの破棄 AuthUser::forget(); // ログイン画面表示 return redirect(route("login")); } } * **showForm()** : ログイン画面表示 * AuthUser::check() で認証チェックします。 * 認証済の場合: * ヘルパー関数redirect()でトップ画面にリダイレクトします。\\ \\ * 未認証の場合: * AuthUser::remember()で自動ログインを試みます。 * 成功の場合: * トップ画面にリダイレクトします。 * 失敗の場合: * ログイン画面( login )にリダイレクトします。 * **login()** : ログイン(認証) * バリデーション( validate() )を実行します。 * バリデーション全体については[[apricot:app:validation|こちら]]を、検証ルールについては[[apricot:app:validation#検証ルール|こちらを]]を参照して下さい。 * バリデーションでエラーの場合: * withInputs()で入力変数をフラッシュ変数に保存します。 * withErrors()でバリデーションのエラーバッグをフラッシュ変数に保存します。 * redirect()でログイン画面にリダイレクトするResponseオブジェクトをします。\\ \\ * Input::all()でフォームデータを取得します。 * AuthUser::authenticate() でユーザ認証を行います。 * 成功した場合: * AuthUser::getPathAfterLogin()でログイン後の画面を取得し、そこにリダイレクトします。 * 失敗した場合: * withInputs()で入力変数をフラッシュ変数に保存します。 * withErrors()でバリデーションのエラーバッグをフラッシュ変数に保存します。 * redirect()でログイン画面にリダイレクトするResponseオブジェクトをします。 * **login()** : ログアウト * AuthUser::forget() で認証セッションを破棄します。 * ログイン画面にリダイレクトします。 AuthUser の使用方法については、[[apricot:ext:user-auth#authuserクラス|こちら]]をご覧ください。 > 認証コントローラのバリデーションは(コードが少量なので)[[apricot:app:validation#インターセプター|インターセプタークラス]]を作らずに自分のクラス内のメソッド( validate() で行っています。後述の「Apricot 拡張: [[apricot:ext:interceptor|インターセプター]]」では、validate()をクロージャにしてアクションと分離した形で再実装します。 \\ ==== ログイン画面 ==== 以下に、ログイン画面で使用するHTMLテンプレートを示します。 {{fa>folder-open-o}} ** /apricot/assets/view ** {{__('messages.app.title')}} {!! DebugBar::renderHead() !!}
{{ __('auth.login.title') }}
@csrf {{-- account --}}
@if($errors->has('account',ValidatorErrorBag::BAG_KEY)) {{$errors->get('account',ValidatorErrorBag::BAG_KEY)}} @endif
{{-- password --}}
@if($errors->has('password',ValidatorErrorBag::BAG_KEY)) {{$errors->get('password',ValidatorErrorBag::BAG_KEY)}} @endif
{{-- remember--}}
{{-- button --}}
@if($errors->count(ErrorBag::DEFAULT_NAME)) @endif
{!! DebugBar::render() !!}
\\ ==== 翻訳テキスト ==== ユーザ認証用の翻訳ファイル( auth.php )にログイン画面用の翻訳テキストを追加します。 {{fa>folder-open-o}} ** apricot/assets/lang/ja ** [ ... ], 'login'=>[ 'title'=>'ログイン', 'account'=>'アカウント', 'password'=>'パスワード', 'remember'=>'ログイン状態を保存する', 'btn_login'=>'ログイン', 'error'=>[ 'no_account'=>'アカウントが見つかりません' ], ], ]; \\ ===== その他の画面修正 ===== ==== layout.blade.php ==== [[apricot:app:top|アプリ作成の準備]]で作成したアプリ全体で使用するHTMLテンプレート [[apricot:app:top#layout.blade.php|layout.blade.php]]を修正します。 {{fa>folder-open-o}} ** /apricot/assets/view ** ... {{-- @if(app('auth.menu',false)) @endif --}} ... * ''