• WEB

Laravel5.2 認証機能について

  • いまこ
    いまこ システムちーむ
  • このエントリーをはてなブックマークに追加

こんにちは、いまこです。

もうずいぶん経ちましたが、Laravel5.2、出ましたね。
Multi-Auth、対応しましたね。
とか言うと古参ぽく感じてしまうかもしれませんが、Laravel歴半年も立っていないペーペーです。
というか、5.2からさわり始めた感じになります 笑

そんなLaravelペーペーな僕ですが、
今回はLaravel5.2の認証系機能について、書いていこうと思います。
GitHubにMulti-Authを使用したサンプルアプリをあげたので、
興味がある方はご覧ください。

デフォルト認証機能について

Laravelにはデフォルトで認証機能が備わっております。
下記artisanコマンドを実行するだけで、ルーティング定義やviewの作成等、
デフォルトで使用する認証機能の全てを用意してくれます。


php artisan make:auth

機能

デフォルトでは下記の機能が備わっております(もっとあるかも…)。

  • 新規登録
  • ログイン
  • ログアウト
  • バリデート
  • パスワードリセット
  • Remember Me(ログイン状態維持)
  • ログインロック(n回ログインに失敗したらn秒間ログインできない)

気が付きましたか?
そうです、退会処理はないのです!!
なので退会処理は自作する必要があります。

ルーティング

app/Http/routes.phpに下記を記述するだけで、ルーティングの定義を行ってくれます。


// app/Http/routes.php

Route::group(['middleware' => ['web']], function () {
    // 認証ルーティング定義
    Route::auth();
});

後記しますが、ルーティングを定義するメソッドを実行しています。
実際使用するときはルーティングを修正する必要があると思うので、
Route::auth()は使用しないか、
名前空間を上手く使用して、対応させる必要があると思います。
ためしにやってみる!!的な感じだと非常に便利です。

コントローラー

Laravel5.2をインストールすると、デフォルトで下記コントローラーが作成されています。

  • app/Http/Controller/AuthController.php
  • app/Http/Congroller/PasswordController.php

こいつらが、Route::auth()で定義したルーティングに対応している感じになります。

Multi-Authについて

複数種類のログインアカウントを管理することが出来る機能です。
例えば、ユーザーと管理者のアカウントを別々に管理する、という感じです。
管理者のみ閲覧可能にする制御等、簡単にすることができます。
基本的には上で説明したLaravelのデフォルト認証機能をベースに、Multi-Authを使用する感じになると思います。

Multi-Authの使い方

  • config/auth.phpに認証アカウント設定追加
  • 設定したアカウントに対応するテーブル作成
  • ルーティング設定
  • ルーティングに対応するController/メソッド作成
  • View作成

やることはこのくらいになります。
あとはお好みでカスタムしていく感じになります。

auth.phpに設定追加

下記のように追加します。
※デフォルトで記述されている設定は削除し、3種類のアカウント設定を行っています


// config/auth.php

// デフォルト設定
'defaults' => [
    'guard' => 'user_accounts',
    'passwords' => 'user_accounts',
],
// アカウントの種類
'guards' => [
    'admin_accounts' => [
        'driver' => 'session',
        'provider' => 'admin_accounts',
    ],
    'client_accounts' => [
        'driver' => 'session',
        'provider' => 'client_accounts',
    ],
    'user_accounts' => [
        'driver' => 'session',
        'provider' => 'user_accounts',
    ],
],
// 対応するモデル
'providers' => [
    'admin_accounts' => [
        'driver' => 'eloquent',
        'model' => App\AdminAccount::class,
    ],
    'client_accounts' => [
        'driver' => 'eloquent',
        'model' => App\ClientAccount::class,
    ],
    'user_accounts' => [
        'driver' => 'eloquent',
        'model' => App\UserAccount::class,
    ],
],
// パスワードリセット時設定
'passwords' => [
    'admin_accounts' => [
        'provider' => 'admin_accounts',
        'email' => 'admin_accounts.emails.password',
        'table' => 'admin_account_password_resets',
        'expire' => 60,
    ],
    'client_accounts' => [
        'provider' => 'client_accounts',
        'email' => 'client_accounts.emails.password',
        'table' => 'client_account_password_resets',
        'expire' => 60,
    ],
    'user_accounts' => [
        'provider' => 'user_accounts',
        'email' => 'user_accounts.emails.password',
        'table' => 'user_account_password_resets',
        'expire' => 60,
    ],
],

テーブル作成

対応するテーブルを作成します。
今回のサンプルだと下記テーブルを作成しています。

  • admin_accounts
  • client_accounts
  • user_accounts
  • admin_account_password_resets
  • client_account_password_resets
  • user_account_password_resets

基本的に1つのアカウントに対して

  • 会員情報テーブル
  • パスワードリセット用テーブル(使用するなら)

が必要となります。

ルーティング

先ほど説明したRoute::auth()が何をしているか見てみましょう。


// Illuminate/Routing/Router.php

public function auth()
{
    // Authentication Routes...
    $this->get('login', 'Auth\AuthController@showLoginForm');
    $this->post('login', 'Auth\AuthController@login');
    $this->get('logout', 'Auth\AuthController@logout');

    // Registration Routes...
    $this->get('register', 'Auth\AuthController@showRegistrationForm');
    $this->post('register', 'Auth\AuthController@register');

    // Password Reset Routes...
    $this->get('password/reset/{token?}', 'Auth\PasswordController@showResetForm');
    $this->post('password/email', 'Auth\PasswordController@sendResetLinkEmail');
    $this->post('password/reset', 'Auth\PasswordController@reset');
}

ただルーティングを定義しているだけですね。
なのでこれをベースとし、各認証のルーティングを定義します。
管理者(admin_accounts)アカウントを例とします。


//app/Http/routes.php

Route::group(['prefix' => 'admin'], function() { 
    // Authentication Routes...
    $this->get('login', 'AdminAccount\AuthController@showLoginForm');
    $this->post('login', 'AdminAccount\AuthController@login');
    $this->get('logout', 'AdminAccount\AuthController@logout');

    // Registration Routes...
    $this->get('register', 'AdminAccount\AuthController@showRegistrationForm');
    $this->post('register', 'AdminAccount\AuthController@register');

    // Password Reset Routes...
    $this->get('password/reset/{token?}', 'AdminAccount\PasswordController@showResetForm');
    $this->post('password/email', 'AdminAccount\PasswordController@sendResetLinkEmail');
    $this->post('password/reset', 'AdminAccount\PasswordController@reset');
}

こんな感じになります。

コントローラー

デフォルトの認証用コントローラーをコピーして、ルーティングに対応させるため、下記ディレクトリ構造にしています。
※admin_accountsを例とします


app -- Http -- Controller -- AdminAccount -- AuthController.php
                                          -- PasswordController.php

AuthController.php修正

以下を行います

  • 名前空間修正
  • モデル修正
  • プロパティ設定
  • テーブル修正

// app/Http/Controller/AdminAccount/AuthController.php

// 名前空間修正
namespace App\Http\Controllers\AdminAccount;
// モデル修正
use App\AdminAccount;
               ・
               ・
               ・

// プロパティ設定
protected $guard = 'admin_accounts';                   // 使用するguard名(デフォルトはauth.phpのデフォルト設定してあるguard)
protected $registerView = 'admin_accounts.register';   // 新規登録画面のview(デフォルトは「auth.register」)
protected $loginView = 'admin_accounts.login';         // ログインページのview(デフォルトは「auth.authenticate」)
protected $redirectTo = '/admin/index';                // ログイン後のリダイレクト先(デフォルトは「/home」)
protected $redirectAfterLogout = '/';                  // ログアウト後のリダイレクト先(デフォルトは「/」)
protected $username = 'email';                         // 認証用のカラム(デフォルトは「email」)
protected $maxLoginAttempts = 5;                       // ログインスロットルとなるまで最高のログイン失敗回数(デフォルトは「5」)
protected $lockoutTime = 60;                           // ログインスロットルとなってからの待ち秒数(デフォルトは60)

               ・
               ・
               ・

// テーブル修正
protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => 'required|max:255',
        'email' => 'required|email|max:255|unique:admin_accounts',
        'password' => 'required|confirmed|min:6',
    ]);
}
               ・
               ・
               ・

// モデル修正
protected function create(array $data)
{
    return AdminAccount::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
    ]);
}

guardを宣言しなければ、auth.phpのdefault設定されてあるguardを使用することになってしまうので、気を付けてください。

PasswordController.php修正

  • プロパティ設定

// app/Http/Controller/AdminAccount/PasswordController.php

protected $guard = 'admin_accounts';                            // auth.guard設定(デフォルトはauth.phpでデフォルト設定したguard)
protected $broker = 'admin_accounts';                           // auth.passwords設定('デフォルトはauth.phpでデフォルト設定したpasswords')
protected $linkRequestView = 'admin_accounts.passwords.email';  // メールアドレス入力view(デフォルトは「auth.passwords.email」)
protected $resetView = 'admin_accounts.passwords.reset';        // パスワードリセットページview(デフォルトは「auth.passwords.reset」or「auth.reset」)
protected $subject = 'Password Reset';                          // リセットリンクメールの件名(デフォルトは「Your Password Reset Link」)
protected $redirectTo = '/';                                    // パスワード変更後のリダイレクト先(デフォルトは「/home」)

broderも宣言しなければ、デフォルト設定が使用されます。

View作成

あとは対応するViewを作成すれば、とりあえず使えるようになると思います。
※サンプルアプリではphp artisan make:authコマンドで生成されたviewをコピーして使用しています

ディレクトリ構造例


resources -- views -- admin_accounts  -- viewファイル
                      client_accounts -- viewファイル
                      user_accounts   -- viewファイル

認証系処理をカスタムする場合

処理を追加したりしたい場合、1から認証処理を作成してもよいのですが、
せっかくデフォルトで備わっているので(あとめんどくさい)、
デフォルトの機能をカスタムしていけばよいと思います。

AuthController.php

AuthController.phpは下記トレイトをuseし、基本的にはそのメソッドを使用しています。


// app/Http/Controllers/Auth/AuthController.php

use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;

なのでちょっと処理を変更したい場合は、メソッドをオーバーライドして使用すればOKです。
例えば、ログイン後にログインした日時を記録したい場合、ログイン処理をオーバーライドし、ログイン日時を記録する処理を追加します。

元のメソッド


// Illuminate/Foundation/Auth/AuthenticatesUsers.php

public function login(Request $request)
{
    $this->validateLogin($request);
    $throttles = $this->isUsingThrottlesLoginsTrait();

    if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
        $this->fireLockoutEvent($request);
        return $this->sendLockoutResponse($request);
    }

    $credentials = $this->getCredentials($request);

    if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
        return $this->handleUserWasAuthenticated($request, $throttles);
    }

    if ($throttles && ! $lockedOut) {
        $this->incrementLoginAttempts($request);
    }

    return $this->sendFailedLoginResponse($request);
}

メソッドをオーバーライドし、処理追加


// app/Http/Controller/AdminAccount/AuthController.php

public function login(Request $request)
{
    $this->validateLogin($request);
    $throttles = $this->isUsingThrottlesLoginsTrait();

    if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
        $this->fireLockoutEvent($request);
        return $this->sendLockoutResponse($request);
    }

    $credentials = $this->getCredentials($request);

    if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
        // ログイン後に現在時間登録(last_login_timeカラムがある前提)
        $date = date('Y-m-d H:i:s');
        AdminAccount::where('id', Auth::guard($this->guard)->user()->id)->update(['last_login_time' => $date]);

        return $this->handleUserWasAuthenticated($request, $throttles);
    }

    if ($throttles && ! $lockedOut) {
        $this->incrementLoginAttempts($request);
    }

    return $this->sendFailedLoginResponse($request);
}

PasswordController.php

PasswordController.phpは下記トレイトをuseしています。


// app/Http/Controllers/Auth/PasswordController.php

use ResetsPasswords;

こっちも同じく、メソッドをオーバーライドすればカスタム可能です。

小ネタ

guestミドルウェア

guestミドルウェアは、指定guardがログイン状態の場合、「/」にリダイレクトさせる処理が書かれています。
ログイン状態の時に、ログインフォームを表示させないためですね。
routes.phpでミドルウェアを指定して使用します。
下記だと、管理者でログイン中は、管理者ログインフォームにアクセスしようとしても、「/」にリダイレクトされるようになります。


Route::group(['middleware' => 'guest:admin_accounts'], function() {
    $this->get('login', 'AdminAccount\AuthController@showLoginForm');
});

便利な機能なのですが、guardミドルウェアを使用すると、何故か指定されたguardとデフォルトのguardの2回処理を行うようになっています。
つまり、デフォルトguardがログイン状態だと、他のguardもログイン状態とみなされ、ログインフォームにアクセスできなくなってしまいます。
これを解消したい場合は、下記のようにguestミドルウェアをカスタムすればOKです。
app/Http/Middleware/RedirectIfAuthenticated.php


public function handle($request, Closure $next, $guard = null)
{
    // $guardが指定されていない場合、認証チェックを行わせない
    if ($guard !== null && Auth::guard($guard)->check()) {
        return redirect('/');
    }
 
    return $next($request);
}

パスワードリセットについて

パスワードリセット機能を使用するためには、下記カラムが存在するテーブルが必要です。

  • email
  • token

逆に言うと、このカラムさえあれば大丈夫なので、アカウント毎にテーブルを分けなくてもいいのでは???
と思ったのですが、emailの重複があった場合、上書き保存されてしまうため、アカウントの数だけテーブルが必要でした。
まあでも、例えばカラムにguardを追加して、登録処理をカスタムすればまとめることが出来ると思うので、やり方次第かなと思います。
ちなみにパスワードリセットが完了したら、レコードは削除されます。

Authファサード

認証系の色々なことが出来るファサードです。

ユーザーがログイン中か


if (Auth::guard('guard名')->check()) {
    // ログイン中
} else {
    // 未ログイン
}

ログインユーザー情報を取得


$user = Auth::guard('guard名')->user();

認証処理


if (Auth::attempt(['email' => '登録されているemail', 'password' => 'ハッシュ化されたパスワード'])) {
    // 認証成功
} else {
    // 認証失敗
}

等々…
詳しくは公式リファレンス
またはコードを読んでください。

最後に

Laravel5.2の認証機能について触れてみました。
今回説明したことは、あくまで一例ですので、
1から認証機能を作成しても良いですし、
ディレクトリ構造も様々な形があると思います。
言ってみれば自由です。
自由に、作りやすいように作ってください。

このエントリーをはてなブックマークに追加

いまこが最近書いた記事

WRITERS POSTS もっと見る

他にもこんな記事が読まれています!

  • WEB
  • マーケティング
  • サーバー・ネットワーク
  • ライフスタイル
  • お知らせ