デフォルト認証機能の動作確認

Tag:

Laravelに標準で組み込まれた認証機能の動作確認をします。

※参考URL
https://readouble.com/laravel/5.2/ja/authentication.html

環境

ここでは、下記手順を実行した後の環境で作業します。

1. Laravel5.2をインストール

2. 「config/app.php」を修正

    'timezone' => 'Asia/Tokyo',
    'locale' => 'ja',

3. 下記パッケージを追加で利用
Laravel Debugbar
comja5

4. .envを修正(DBの設定、メールのドライバをログに変更)

DB_DATABASE=homestead
DB_USERNAME=ユーザ名
DB_PASSWORD=パスワード

MAIL_DRIVER=log

※DBを作るのが面倒なら以下でもOK

DB_CONNECTION=sqlite
#DB_HOST=127.0.0.1
DB_PORT=3306
#DB_DATABASE=homestead
#DB_USERNAME=homestead
#DB_PASSWORD=secret

MAIL_DRIVER=log
touch database/database.sqlite

5. サーバー立ち上げ

php artisan serve

「make:auth」コマンドで認証機能を実装

Laravel5.2からartisanで「make:auth」コマンドを利用できるようになりました。

「make:auth」コマンドを利用すると、認証機能を実装するために必要なビューなどを作成してくれます。
laravel_auth

・8つのViewが作成されています。
・1つのController(HomeController)が作成されています。
・「app\Http\routes.php」が更新されています。

ルーティング一覧を確認

「make:auth」コマンドの実行により、「app\Http\routes.php」には下記内容が追記されました。

Route::auth();

Route::get('/home', 'HomeController@index');

authメソッドは、「Illuminate\Routing\Router.php」に記述されています。

authメソッドの記述を確認
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');
}

追加されたルーティング情報を確認してみます。下記、赤枠で囲まれた箇所が追加されたルーティング情報です。
laravel_auth1

Middlewareに「auth」と「guest」の設定がされていますね。「auth」は、ログイン中のときだけ実行可能であることを表しています。「guest」は、非ログイン中のときだけ実行可能であることを表しています。

なお、Middlewareの指定方法は2つあります。
・ルート定義に指定
・コントローラのコンストラクタで指定

テーブル作成

デフォルト認証機能に必要なテーブルを作成します。migrationファイルは、デフォルトで用意されているので、下記コマンドを実行するだけでテーブルが作成されます。

php artisan migrate

laravel_auth2

「migrations」「password_resets」「users」というテーブルが作成されました。

「users」テーブルの内容は以下の通りです。
laravel_auth_users
laravel_auth_users2

「password_resets」テーブルの内容は以下の通りです。
laravel_auth_password_resets
laravel_auth_password_resets2

認証機能の動作確認

認証機能を動作させるための準備ができたので、動作確認を始めます。

非ログイン中の状態で「/home」にアクセス
非ログイン中の状態で「/home」にアクセスしてみます。すると、下記のように「/login」にリダイレクトされました。
laravel_auth3

なぜリダイレクトされたかというと、HomeControllerのコンストラクタで、authミドルウェアを利用しているためです。

public function __construct()
{
    $this->middleware('auth');
}

authミドルウェアを利用すると、非ログイン中の場合、処理を実行させないようにできます。

具体的にソースを見てみます。まず、authミドルウェアの処理がどこに記述されているか探します。「app\Http\Kernel.php」で確認できます。

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

2行目に記述されていますね。「app\Http\Middleware\Authenticate.php」を確認してみます。

public function handle($request, Closure $next, $guard = null)
{
    if (Auth::guard($guard)->guest()) {
        if ($request->ajax() || $request->wantsJson()) {
            return response('Unauthorized.', 401);
        } else {
            return redirect()->guest('login');
        }
    }

    return $next($request);
}

3行目でログイン中であるか判定しています。非ログイン中であれば、7行目で、「/login」にリダイレクトさせていることがわかります。

ユーザー登録
「/register」にアクセスしてユーザ登録をします。
laravel_auth4

フォームに必要情報を入力して、「Register」をクリックすると、ログインされた状態で「/」へリダイレクトされました。

userテーブルを確認

userテーブルを見てみると、下記のようにレコードが追加されていました。
laravel_auth5

cookieとsessionを確認

cookieも設定されていました。
laravel_auth6

対応するsession情報は、「storage\framework\sessions」配下に格納されています。
laravel_auth7
session情報は、ログイン中であるか判定するのに利用されます。

ソースを確認

POSTメソッドで「/register」にアクセスしたとき、実行されるActionは「App\Http\Controllers\Auth\AuthController@register」です。なので、「App\Http\Controllers\Auth\AuthController」を見てみます。

「AuthController」自体にはregisterメソッドが記述されていません。下記のようにトレイトを利用しています。

    use AuthenticatesAndRegistersUsers, ThrottlesLogins;

「AuthenticatesAndRegistersUsers」を見てみます。NetBeansであれば、下記のように「AuthenticatesAndRegistersUsers」を選択状態にして、「Ctrl+B」をクリックすれば、宣言に移動できますね。
laravel_auth_netbeanse

「AuthenticatesAndRegistersUsers」でもトレイトを利用しているようです。

namespace Illuminate\Foundation\Auth;

trait AuthenticatesAndRegistersUsers
{
    use AuthenticatesUsers, RegistersUsers {
        AuthenticatesUsers::redirectPath insteadof RegistersUsers;
        AuthenticatesUsers::getGuard insteadof RegistersUsers;
    }
}

「RegistersUsers」を見てみるとregisterメソッドがありました。

public function register(Request $request)
{
    $validator = $this->validator($request->all());

    if ($validator->fails()) {
        $this->throwValidationException(
            $request, $validator
        );
    }

    Auth::guard($this->getGuard())->login($this->create($request->all()));

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

3行目でバリデーションしてます。validatorメソッドは、「app\Http\Controllers\Auth\AuthController.php」に記述されています。

validatorメソッドの記述を確認
protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => 'required|max:255',
        'email' => 'required|email|max:255|unique:users',
        'password' => 'required|min:6|confirmed',
    ]);
}

10行目でDBにユーザ情報を登録して、ログインしています。Auth::guard()部分では、SessionGuard(Illuminate\Auth\SessionGuard)クラスのオブジェクトを取得してます。SessionGuardクラスのloginメソッドの引数内では、createメソッドを実行してますね。createメソッドは、「app\Http\Controllers\Auth\AuthController.php」に記述されています。

createメソッドの記述を確認
protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
    ]);
}

12行目でリダイレクトしています。redirectPathメソッドでは以下のようにパスを決定してます。

redirectPathメソッドの記述を確認
public function redirectPath()
{
    if (property_exists($this, 'redirectPath')) {
        return $this->redirectPath;
    }

    return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}

まず、「redirectPathプロパティ」が設定されていば、その値を返します。
次に、「redirectToプロパティ」が設定されていれば、その値を返します。
どちらも設定されていなければ、「/home」を返します。

ログアウト
ユーザ登録するとログイン中となるので、一度ログアウトします。

ログイン中のセッション情報と、ログアウト後のセッション情報を見比べてみます。

ログイン中

a:5:{s:6:"_token";s:40:"3abllHCVpjSe9N0xsRvSoW2xFq3YgtPB7Ds25XtN";s:9:"_previous";a:1:{s:3:"url";s:21:"http://localhost:8000";}s:5:"flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:50:"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d";i:1;s:9:"_sf2_meta";a:3:{s:1:"u";i:1465555073;s:1:"c";i:1465554403;s:1:"l";s:1:"0";}}

ログアウト後

a:4:{s:6:"_token";s:40:"3abllHCVpjSe9N0xsRvSoW2xFq3YgtPB7Ds25XtN";s:9:"_previous";a:1:{s:3:"url";s:21:"http://localhost:8000";}s:5:"flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:9:"_sf2_meta";a:3:{s:1:"u";i:1465555875;s:1:"c";i:1465554403;s:1:"l";s:1:"0";}}

「login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d」の情報が削除されていますね。

ログイン
ログインページに直接アクセスした場合は、ログイン後「/」にアクセスされます。「app\Http\Controllers\Auth\AuthController.php」にて下記のように設定しているためです。

protected $redirectTo = '/';

非ログイン中、ログインが必要なページにアクセスして、ログインページにリダイレクトされた場合、動作が異なります。ログイン後は、ログイン前にアクセスしようとしたページにリダイレクトしてくれます。

例えば、未ログイン状態で「/home」にアクセスすると「/login」にリダイレクトされます。「/login」のページからログインすると、ログイン前にアクセスしようとした「/home」にリダイレクトしてくれます。

ソースを確認

POSTメソッドで「/login」にアクセスしたとき、実行されるActionは「App\Http\Controllers\Auth\AuthController@login」です。なので、「App\Http\Controllers\Auth\AuthController」を見てみます。

「AuthController」自体にはloginメソッドが記述されていません。loginメソッドは、「Illuminate\Foundation\Auth\AuthenticatesUsers」に記述されています。

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

    // If the class is using the ThrottlesLogins trait, we can automatically throttle
    // the login attempts for this application. We'll key this by the username and
    // the IP address of the client making these requests into this application.
    $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 the login attempt was unsuccessful we will increment the number of attempts
    // to login and redirect the user back to the login form. Of course, when this
    // user surpasses their maximum number of attempts they will get locked out.
    if ($throttles && ! $lockedOut) {
        $this->incrementLoginAttempts($request);
    }

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

3行目でメールアドレスとパスワードが入力されているか判定してます。
18行目のattemptメソッドでログイン処理を行ってます。セッション情報がここで更新されます。
ログインに成功した場合、19行目のhandleUserWasAuthenticatedメソッドが実行されます。

protected function handleUserWasAuthenticated(Request $request, $throttles)
{
    if ($throttles) {
        $this->clearLoginAttempts($request);
    }

    if (method_exists($this, 'authenticated')) {
        return $this->authenticated($request, Auth::guard($this->getGuard())->user());
    }

    return redirect()->intended($this->redirectPath());
}

11行目でリダイレクトしてますね。intendedメソッドの処理は以下の通りです。

public function intended($default = '/', $status = 302, $headers = [], $secure = null)
{
    $path = $this->session->pull('url.intended', $default);

    return $this->to($path, $status, $headers, $secure);
}

3行目でセッション情報から「url.intended」を取得してます。未ログイン状態で「/home」にアクセスした場合、以下のように、「url.intended」には「http://localhost:8000/home」という情報が設定されていますね。

a:6:{s:6:"_token";s:40:"VFxnmJz5hunnsOyjOzozr0PLamPRp67bTBzAQ3sY";s:3:"url";a:1:{s:8:"intended";s:26:"http://localhost:8000/home";}s:9:"_previous";a:1:{s:3:"url";s:21:"http://localhost:8000";}s:5:"flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:50:"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d";i:1;s:9:"_sf2_meta";a:3:{s:1:"u";i:1465552588;s:1:"c";i:1465551696;s:1:"l";s:1:"0";}}

これにより、ログイン後は、ログイン前にアクセスしようとした「/home」にアクセスしてくれます。

「Remember Me」を選択した状態でログイン
「Remember Me」を選択した状態でログインしてみます。
laravel_auth14

すると、「users」テーブルのremember_tokenが更新されます。
laravel_auth12

クッキー側にも同じトークンが設定されました。
laravel_auth13

これで、ログインセッションの有効期限が切れても、ログインが必要なページにログインせずにアクセスできます。サーバー側でセッションファイルを削除するなどして確認できます。

ログアウトするとクッキーのトークンが破棄されて、「users」テーブルのremember_tokenの値も更新されます。

パスワード変更
本人確認のため、メールアドレスを入力して、リセットボタンをクリックします。
laravel_auth8

成功メッセージが表示されました。
laravel_auth9

「password_resets」テーブルを確認すると、下記のようにレコードが追加されていました。
laravel_auth10

メールのドライバをlogに設定したので、「strage/logs/laravel.log」を確認します。下記のように、送信メール内容が追記されています。

[2016-06-10 20:58:35] local.DEBUG: Message-ID: <b64840fb666a8bab9c30a4c8b767724b@localhost>
Date: Fri, 10 Jun 2016 20:58:34 +0900
Subject: Your Password Reset Link
From: 
To: dnweb@test.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Click here to reset your password: <a href="http://localhost:8000/password/reset/33e643f792e86b9c0ef0ff0cdb25d257e7f093ceb38be2bdbe815f9e6d2cdc65?email=dnweb%40test.com"> http://localhost:8000/password/reset/33e643f792e86b9c0ef0ff0cdb25d257e7f093ceb38be2bdbe815f9e6d2cdc65?email=dnweb%40test.com </a>

メールの最下行に記述されているリンクをクリックすると、下記ページが表示されます。email情報が入力された状態です。
laravel_auth11

ここで、他のユーザのパスワードを更新できないか確認するため、入力されたemail情報を変更して登録してみます。すると、下記のように「このパスワードリセットトークンは無効です。」というエラーメッセージが表示されます。email情報も、元のemail情報が再度入力されてますね。
laravel_auth16
今度は、email情報を変更しないで、パスワード変更処理を進めます。

パスワード変更処理ですが、「users」テーブルからemailの値が対応するレコードのpasswordを変更します。無事パスワードを変更し終えると「password_resets」テーブルに存在する、同一トークンのレコードが削除され、「/home」へリダイレクトされます。

なおトークン保存時間は60分です。「config/auth.php」で変更可能です。

補足:「make:auth」コマンドで実装されたView

「resources\views」配下のテンプレート 概要
auth\emails\password.blade.php パスワードリセット本人確認用送信メール
auth\passwords\email.blade.php パスワードリセットメールアドレス入力画面
「/password/email」で利用
auth\passwords\reset.blade.php パスワードリセット画面
「/password/reset」で利用
auth\login.blade.php ログイン画面
「/login」で利用
auth\register.blade.php 登録画面
「/register」で利用
layouts\app.blade.php ベースレイアウト
views\home.blade.php 「/home」で利用
views\welcome.blade.php 「/」で利用

各viewの記述は以下のようになります。

resources\views\auth\emails\password.blade.php
Click here to reset your password: <a href="{{ $link = url('password/reset', $token).'?email='.urlencode($user->getEmailForPasswordReset()) }}"> {{ $link }} </a>
resources\views\auth\passwords\email.blade.php
@extends('layouts.app')

<!-- Main Content -->
@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Reset Password</div>
                <div class="panel-body">
                    @if (session('status'))
                        <div class="alert alert-success">
                            {{ session('status') }}
                        </div>
                    @endif

                    <form class="form-horizontal" role="form" method="POST" action="{{ url('/password/email') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    <i class="fa fa-btn fa-envelope"></i> Send Password Reset Link
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
resources\views\auth\passwords\reset.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Reset Password</div>

                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ url('/password/reset') }}">
                        {{ csrf_field() }}

                        <input type="hidden" name="token" value="{{ $token }}">

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ $email or old('email') }}">

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Password</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password">

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
                            <label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation">

                                @if ($errors->has('password_confirmation'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password_confirmation') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    <i class="fa fa-btn fa-refresh"></i> Reset Password
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
resources\views\auth\login.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Login</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Password</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password">

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <div class="checkbox">
                                    <label>
                                        <input type="checkbox" name="remember"> Remember Me
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    <i class="fa fa-btn fa-sign-in"></i> Login
                                </button>

                                <a class="btn btn-link" href="{{ url('/password/reset') }}">Forgot Your Password?</a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
resources\views\auth\register.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Register</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                            <label for="name" class="col-md-4 control-label">Name</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}">

                                @if ($errors->has('name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Password</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password">

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
                            <label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation">

                                @if ($errors->has('password_confirmation'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password_confirmation') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    <i class="fa fa-btn fa-user"></i> Register
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
resources\views\layouts\app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel</title>

    <!-- Fonts -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css" integrity="sha384-XdYbMnZ/QjLh6iI4ogqCTaIjrFk87ip+ekIjefZch0Y+PvJ8CDYtEs1ipDmPorQ+" crossorigin="anonymous">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700">

    <!-- Styles -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    {{-- <link href="{{ elixir('css/app.css') }}" rel="stylesheet"> --}}

    <style>
        body {
            font-family: 'Lato';
        }

        .fa-btn {
            margin-right: 6px;
        }
    </style>
</head>
<body id="app-layout">
    <nav class="navbar navbar-default navbar-static-top">
        <div class="container">
            <div class="navbar-header">

                <!-- Collapsed Hamburger -->
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
                    <span class="sr-only">Toggle Navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>

                <!-- Branding Image -->
                <a class="navbar-brand" href="{{ url('/') }}">
                    Laravel
                </a>
            </div>

            <div class="collapse navbar-collapse" id="app-navbar-collapse">
                <!-- Left Side Of Navbar -->
                <ul class="nav navbar-nav">
                    <li><a href="{{ url('/home') }}">Home</a></li>
                </ul>

                <!-- Right Side Of Navbar -->
                <ul class="nav navbar-nav navbar-right">
                    <!-- Authentication Links -->
                    @if (Auth::guest())
                        <li><a href="{{ url('/login') }}">Login</a></li>
                        <li><a href="{{ url('/register') }}">Register</a></li>
                    @else
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                                {{ Auth::user()->name }} <span class="caret"></span>
                            </a>

                            <ul class="dropdown-menu" role="menu">
                                <li><a href="{{ url('/logout') }}"><i class="fa fa-btn fa-sign-out"></i>Logout</a></li>
                            </ul>
                        </li>
                    @endif
                </ul>
            </div>
        </div>
    </nav>

    @yield('content')

    <!-- JavaScripts -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js" integrity="sha384-I6F5OKECLVtK/BL+8iSLDEHowSAfUo76ZL9+kGAgTRdiByINKJaqTPH/QVNS1VDb" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
    {{-- <script src="{{ elixir('js/app.js') }}"></script> --}}
</body>
</html>
resources\views\home.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <div class="panel panel-default">
                <div class="panel-heading">Dashboard</div>

                <div class="panel-body">
                    You are logged in!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
resources\views\welcome.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <div class="panel panel-default">
                <div class="panel-heading">Welcome</div>

                <div class="panel-body">
                    Your Application's Landing Page.
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

補足:Authファサード

Authファサードの実際のクラスは、「Illuminate\Auth\AuthManager」です。「Illuminate\Auth\AuthManager」内で、マジックメソッドの「__callメソッド」が定義されており、「Illuminate\Auth\SessionGuardクラス」のインスタンスが利用されます。

// 認証済みユーザーを取得
$user = Auth::user();

// 現在のユーザーが認証されているか判定
if (Auth::check()) {
}

// 認証(ログイン)
Auth::attempt($credentials);

// 特定のUserインスタンスを認証(ログイン)
Auth::login($user);

// そのリクエスト間だけ認証(ログイン)
Auth::once($credentials);

// ログアウト
Auth::logout();

authヘルパーも用意されています。

// 認証済みユーザーを取得
$user = auth()->user();

authヘルパーは次のような処理となっています。

function auth($guard = null)
{
    if (is_null($guard)) {
        return app(AuthFactory::class);
    } else {
        return app(AuthFactory::class)->guard($guard);
    }
}

補足:config/auth.php

まずは、デフォルトの設定を見てみます(comja5で日本語化してます)。

config/auth.php


<?php

return [

    /*
    |--------------------------------------------------------------------------
    | 認証デフォルト
    |--------------------------------------------------------------------------
    |
    | このオプションはアプリケーションで用いる認証のデフォルト"guard"と
    | パスワードリセットオプションをコントロールします。これらのデフォルト値は
    | 自由に変更できますが、ほとんどのアプリケーションではこのままでよいでしょう。
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | 認証Guard
    |--------------------------------------------------------------------------
    |
    | 次に、アプリケーションの全認証Guardを定義します。
    | もちろん、「セッション」ストレージとEloquentユーザーを元に利用する、
    | もちろん、セッションストレージとEloquentユーザーを元に利用する、
    |
    | 全認証ドライバーはユーザープロバイダーを持っています。アプリケーションで
    | ユーザー情報を保管するために使用しているデータベースやストレージ
    | メカニズムから実際にどのようにユーザーを取り出すかをドライバーは定義しています。
    |
    | サポートドライバー: "session", "token"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | ユーザープロバイダー
    |--------------------------------------------------------------------------
    |
    | 全認証ドライバーはユーザープロバイダーを持っています。アプリケーションで
    | ユーザー情報を保管するために使用しているデータベースやストレージ
    | メカニズムから実際にどのようにユーザーを取り出すかをドライバーは定義しています。
    |
    | 複数のユーザーテーブルやモデルが存在している場合、それぞれの
    | モデルやテーブルを表す複数のソースを設定してください。それからこうした
    | ソースへあなたが定義した認証Guardを追加でアサインする必要があるでしょう。
    |
    | サポートドライバー: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | パスワードリセット
    |--------------------------------------------------------------------------
    |
    | ここではパスワードリマインダーの設定を行います。それにはパスワード
    | メールにリセットメールのビューも含まれます。また、リセット
    | トークンを保存しておくためのテーブル名も指定可能です。
    |
    | アプリケーションで複数のユーザーテーブルやモデルを使用している場合、
    | 複数のパスワードリセット設定が必要になるでしょう。そして特定の
    | ユーザータイプに応じて、パスワードリセット設定を分けたくなるでしょう。
    |
    | 有効時間の"expire"に指定する分数は、良く考えてください。
    | このトークン保存時間はセキュリティー機能で、短い時間ほど
    | 安全になります。ですが、必要に応じ変更可能です。
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'email' => 'auth.emails.password',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],

];

認証デフォルトは、「Illuminate\Auth\AuthManager」のgetDefaultDriverメソッドで参照しています。getDefaultDriverメソッドは、guardメソッドで利用されています。

// Illuminate\Auth\AuthManagerの抜粋

public function guard($name = null)
{
    $name = $name ?: $this->getDefaultDriver();

    return isset($this->guards[$name])
                ? $this->guards[$name]
                : $this->guards[$name] = $this->resolve($name);
}

public function getDefaultDriver()
{
    return $this->app['config']['auth.defaults.guard'];
}

つまり、デフォルトだと以下は同じになります。

Auth::guard();
Auth::guard("web");

Laravel5.2からMulti-Auth認証が使えるようになりました。例えば、一般ユーザと管理者で別々に認証を管理したい場合以下のようにします。(テーブルやEloquentも別途作成します。)

config/auth.php(Multi-Auth認証例)


<?php

return [

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
        // 追加
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

        // 追加
        'admin' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],
    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'email' => 'auth.emails.password',
            'table' => 'password_resets',
            'expire' => 60,
        ],
        // パスワードリセットも使うのなら追加
        'admin' => [
            'provider' => 'admins',
            'email' => 'auth.emails.password',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],
];
// 一般ユーザーとして認証されているか判定
if (Auth::guard('web')->check()) {
}

// 管理者として認証されているか判定
if (Auth::guard('admin')->check()) {
}

authヘルパーを使うなら

// 一般ユーザーとして認証されているか判定
if (auth('web')->check()) {
}

// 管理者として認証されているか判定
if (auth('admin')->check()) {
}

まとめ

クラス図

デフォルトの認証関連で利用するクラスなどをまとめました。
laravel_def_auth_image2
トレイトのメソッドをオーバーライドすることで、ログイン処理などカスタマイズできます。

画面遷移とリダイレクト設定

リダイレクト先はプロパティを設定することで変更できます。

タイミング コントローラ プロパティ デフォルト

ユーザー登録後、
ログイン後(※1)
AuthController redirectPath
(redirectToでも可。redirectPathが優先)
/home(※2)

パスワードリセット後
PasswordController redirectPath
(redirectToでも可。redirectPathが優先)
/home

ログアウト後
AuthController redirectAfterLogout /
※1
非ログイン中、リダイレクトされてログインページにアクセスされた場合は、ログイン後、非ログイン中にアクセスしようとしたページにリダイレクトされます。
※2
デフォルトで存在する「App\Http\Controllers\Auth\AuthController」で「protected $redirectTo = '/';」とリダイレクト先を変更しているため、「/」にリダイレクトします。

スポンサーリンク