読者です 読者をやめる 読者になる 読者になる

tanaka's Programming Memo

プログラミングについてのメモ。

Laravel5.3でSentinelを利用する(5)ログインとログアウト(2016/12/31更新)

PHP Sentinel Laravel

前へ | 次へ

ログイン処理を、Sentinelに変更します。ルートは前の手順ですでに作成済みなので、postに対するコントローラーの作成を行います。

(2016/11/8 エラーを withErrors で渡すように修正)
(2016/12/15 HTMLのID 'loginForm'がキャメルケースだったので、ケバブケースに修正)
(2016/12/21 テストにwantToを追加)
(2016/12/31 ログアウト後表示するページを home から login に変更)


ログイン

ログインのテストコードの作成

ログインに関する処理のテストコードを用意します。

まずは、ボタンを押すフォームを指定するためのIDをformタグに追加します。

  • resources/views/auth/login.blade.php をエディターで開く
  • 「<form」から始まる行を探して、以下のようにID属性を追加する
                    <form id="login-form" class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">

続けて、Cestファイルを作成します。

  • ターミナルから以下を実行して、ログイン用のCestファイルを作成
composer exec codecept g:cest functional Login
  • tests/functional/LoginCest.php をエディターで開いて、以下のコードにする(2016/12/21 テストにwantToを追加)
<?php

use Activation;
use Sentinel;

class LoginCest
{
    // ユーザー情報
    private $cre = [
        'name' => 'ログイン',
        'email' => 'login@test.com',
        'password' => 'password'
    ];

    public function _before(FunctionalTester $I)
    {
        // ユーザーを登録
        Sentinel::registerAndActivate($this->cre);

    }

    public function _after(FunctionalTester $I)
    {
    }

    // tests
    public function tryToTest(FunctionalTester $I)
    {
        // 無効なログインテスト
        $I->wantTo(' 未登録ユーザーのログイン失敗');
        $I->amOnPage('/login');
        $I->submitForm('#login-form', [
            'email' => 'nobody@test.com',
            'password' => 'notentry'
        ]);
        $I->see(trans('sentinel.login_failed'));

        // ログインの成功テスト
        $I->wantTo(' ログイン動作の確認.');
        $I->amOnPage('/login');
        $I->submitForm('#login-form', $this->cre);
        $I->seeInCurrentUrl('/home');
    }
}

npm test でテストを走らせると、まずはエラーになります。機能を実装してテストが通るようにします。

必要なメッセージの追加

ログインに関連するメッセージを追加します。

  • resources/lang/ja/sentinel.php をエディターで開く
  • 以下のメッセージを追加
    // ログイン関連
    'not_activation' => 'ユーザー登録が完了していません。登録したメールアドレスに、登録確認用のメールを送信してあります。メールを開いて、リンクをクリックしてください。メールを紛失した場合は、下のリンクからメールを再送できます。',
    'login_failed' => 'ログインに失敗しました。正しいメールアドレスとパスワードでログインしてください。',
    'login_throttling' => 'ログイン失敗が規定回数を越えました。一定時間、IPを凍結します。',

ログイン処理の実装

既存のログイン処理のコードを、Sentinelに合わせて書き換えます。

アクティベーションされていない時や、ログイン失敗時の処理もまとめて作成します。アクティベーションされていない時には、アクティベーションコードの再送信をする指示をビューに投げていますが、この辺りの実装は後ほど行います。

  • app/Http/Controllers/Auth/LoginController.php をエディターで開く
  • ファイルの中身を、以下のように書き換える(エラーをwithErrorsで渡すように修正)
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Cartalyst\Sentinel\Checkpoints\NotActivatedException;
use Cartalyst\Sentinel\Checkpoints\ThrottlingException;
use Sentinel;

class LoginController extends Controller
{
    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest', ['except' => 'logout']);
    }

    /**
     * ログイン処理
     */
    public function login(Request $request) {
        // バリデーション
        $this->validate($request, [
            'email' => 'required|email|max:255',
            'password' => 'required|between:6,255',
            'remember' => 'boolean',
        ]);

        // 認証処理
        try {
            $this->userInterface = Sentinel::authenticate([
                'email' => $request['email'],
                'password' => $request['password']
            ], $request['remember']);
        } catch (NotActivatedException $notactivated) {
            return view('auth.login', [
                'resend_code' => $request['email']
            ])->withErrors([trans('sentinel.not_activation')]);
        } catch (ThrottlingException $throttling) {
            return view('auth.login')->withErrors([trans('sentinel.login_throttling')."[あと".$throttling->getDelay()."秒]"]);
        }

        if (!$this->userInterface) {
            // エラー
            return view('auth.login')->withErrors([trans('sentinel.login_failed')]);
        }

        return redirect($this->redirectTo);
    }
}

以上で、ログイン、未アクティベーション、IP凍結に対応しました。 npm test で実行したテストが成功します。また、 http://localhost:8000 を開いて、先に登録したユーザーでログインを試すと、今度は home ページに移動して、ログインが成功します。


ログアウト

ログアウトに対応させます。

テストの作成

テストはシンプルなので、Loginのものに実装します。

  • tests/functional/LoginCest.php をエディターで開く
  • tryToTest メソッドのログイン用のテストコードの下に、以下のコードを追加する(2016/12/21 テストにwantToを追加)
        // POSTでログアウトテスト
        $I->wantTo(' ログアウトの動作確認.');
        $I->amOnPage('/login');
        $I->submitForm('#login-form', $this->cre);
        $I->submitForm('#logout-form', []);
        $I->seeInCurrentUrl('/login');

        // GETでログアウトテスト
        $I->wantTo(' GETでのログアウトの動作確認.');
        $I->amOnPage('/logout');
        $I->seeInCurrentUrl('/login');

ルートの追加

ログアウトのルートを設定します。フォームからのリクエストは、postで送信されるので、getとpostの双方にルートを設定します。

  • routes/web.php をエディターで開く
  • 以下のルートをログイン関連の下あたりに追加する
// ログアウト用のルート
Route::match(['get', 'post'], 'logout', 'Auth\LoginController@logout')->name('logout');

コントローラーを追加する

コントローラーはシンプルなので、Loginのものに追加します。

  • app/Http/Auth/LoginController.php
  • 以下の変数をクラス内に追加する
    /**
     * ログアウト後に表示するページ
     */
    protected $logoutTo = '/login';
  • 以下のlogoutメソッドをクラスに追加する(2016/12/31 ログアウト後のリダイレクト先を logoutTo に変更)
    /**
     * ログアウト処理
     */
    protected function logout(Request $request) {
        Sentinel::logout();

        return redirect($this->logoutTo);
    }

ログアウトの実装完了です。 npm test を実行して、成功することを確認して下さい。

以上で、ログインとログアウトが実装できました。 http://localhost:8000/ を開いて、ログインとログアウトを試してください。テストが通っているので、問題なく成功します。



これで最低限の流れは実装できました。残りは、アクティベーションコードの再送や、パスワードの対応などです。



前へ | 次へ