LoginSignup
4
3

More than 3 years have passed since last update.

Laravelの認証(web画面)

Last updated at Posted at 2020-07-21

目次

Laravelの記事一覧は下記
PHPフレームワークLaravelの使い方

Laravelバージョン

動作確認はLaravel Framework 7.19.1で行っています

前提条件

eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

LaravelでJavaScript、CSSを使う
本記事は上記が完了している前提で書かれています
npm installを上記で完了しています
npm installが完了している前提で書かれています

Laravelでメール送信する
上記記事でLaravelからメール送信できるようにしています
本記事はメール送信ができるようになっている前提で書かれています

Laravelでデータベースを扱う準備をする
Laravelでテーブル作成
Laravelで初期データ投入
Laravelでデータベースを操作する(Eloquent編)
本記事は上記ので作成したデータベースとレコードを使用します

認証に必要なソース生成

コマンドラインで
cd sample
composer require laravel/ui
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します

または、composer.jsonを修正

composer.json
‥‥
    "require": {
‥‥
        "laravel/tinker": "^2.0",
        "laravel/ui": "^2.1"
    },
‥‥

"laravel/ui": "^2.1"追加しました
コマンドラインで
cd sample
composer update
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します

上記composer require laravel/uicomposer updateのどちらかをしてください

コマンドラインで
php artisan ui vue --auth
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Http/Controllers/Auth、/sample/resources/views/authに多くのファイルが現れます
/sample/database/migrations/xxxx_xx_xx_xxxxxx_create_password_resets_table.phpも現れます
/sample/routes/web.phpに2行
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
追記されています

Model修正

(1) /sample/app/User.phpを/sample/app/Models/User.phpに移動します
/sample/app/ModelsフォルダはLaravelでデータベースを操作する(Eloquent編)で作成しました

(2) /sample/app/Models/User.php修正
namespace App;namespace App\Models;に修正

(3) /sample/config/auth.php修正

auth.php
‥‥
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
‥‥

providers->users->modelをApp\Models\User::classに修正

(4) /sample/app/Http/Controllers/Auth/RegisterController.php修正
use App\User;use App\Models\User;に修正

(5) /sample/database/factories/UserFactory.php修正
use App\User;use App\Models\User;に修正

JavaScript、CSSビルド実行

コマンドラインで
cd sample
npm run dev

動作確認その1

http://localhost/laravelSample/
画面右上にLOGIN、REGISTERのリンクが現れました
REGISTERをクリックし、Name、E-Mail Address、Password、Confirm Passwordを入力してRegisterボタンをクリック
MySQLでlaravel_sampleデータベースを確認してみましょう
select * from users;
レコードが入っています

右上のユーザー名プルダウンからLogoutをクリック
ログアウトできました

右上のユーザー名プルダウンからLOGINをクリック
先ほど登録したE-Mail Address、Passwordを入力し、Loginボタンをクリック
ログインできました

自動生成物の確認

先ほど実行したphp artisan ui vue --authで生成されたソースの中身を確認しましょう
(1) web.phpの確認
/sample/routes/web.phpに追記されたAuth::routes();
/sample/vendor/laravel/ui/src/AuthRouteMethods.phpのauth()メソッドの戻り値を実行します
AuthRouteMethods#authはAuthRouteMethods#resetPassword、AuthRouteMethods#confirmPassword、AuthRouteMethods#emailVerification
を状況にしたがって呼び出します
見ての通り、AuthRouteMethods.phpは認証に必要なルーティングが書かれているだけです
自動生成されたルーティングをまとめると下記になります

// ログイン
get('login', 'Auth\LoginController@showLoginForm')
post('login', 'Auth\LoginController@login');

// ログアウト
post('logout', 'Auth\LoginController@logout')

// ユーザー登録
get('register', 'Auth\RegisterController@showRegistrationForm')
post('register', 'Auth\RegisterController@register');

// パスワード再発行メール送信前の操作
get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')
post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')
// パスワード再発行メール送信後の操作
get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')
post('password/reset', 'Auth\ResetPasswordController@reset')

// 特定URLアクセス時のパスワード入力要求
get('password/confirm', 'Auth\ConfirmPasswordController@showConfirmForm')
post('password/confirm', 'Auth\ConfirmPasswordController@confirm');

// ユーザー登録後のメールアドレス確認
get('email/verify', 'Auth\VerificationController@show')
get('email/verify/{id}/{hash}', 'Auth\VerificationController@verify')
post('email/resend', 'Auth\VerificationController@resend')

get('/home', 'HomeController@index')

また、web.phpに定義しているルーティングに->middleware('auth');をつけると認証済みユーザーのみアクセスできるurlになります

Route::get('sample/jscss', 'SampleController@jscss')->middleware('auth');
これでhttp://localhost/laravelSample/sample/jscssにアクセスしようとするとログイン認証を要求されます

(2) Controllerクラスの確認
上記ルーティングに書かれているコントローラークラスの中を見ると実処理はトレイトに書かれていることがわかります
各コントローラーの実処理が書かれているトレイトは/sample/vendor/laravel/ui/auth-backendに入っています
対応表です

機能 app/Http/Controllers/Auth配下のコントローラー vendor/laravel/ui/auth-backend配下のトレイト
特定URLアクセス時のパスワード入力要求 ConfirmPasswordController.php ConfirmsPasswords.php
パスワード再発行メール送信前の操作 ForgotPasswordController.php SendsPasswordResetEmails.php
ログイン、ログアウト LoginController.php AuthenticatesUsers.php
ユーザー登録 RegisterController.php RegistersUsers.php
パスワード再発行メール送信後の操作 ResetPasswordController.php ResetsPasswords.php
ユーザー登録後のメールアドレス確認 VerificationController.php VerifiesEmails.php

トレイト内の処理は読めば分かるので、紹介はすこしだけにします

・RegistersUsers.phpのregister
トレイトvendor/laravel/ui/auth-backend/RegistersUsers.phpのregisterメソッドは、app/Http/Controllers/Auth/RegisterController.phpのregisterメソッドとなります。つまり、ユーザー登録メソッドです
event(new Registered($user = $this->create($request->all())));
$this->create($request->all())部分でRegisterController.phpのcreateが呼ばれ、その中でUser::createが実行されます。User::createでusersテーブルにレコードがinsertされます
$this->guard()はAuth::guard()が実行され、SessionGuardが返ってきます。$this->guard()->login($user);でログインです

・guard
guardは認証まわりの処理が書かれたクラスです
Auth::guard()の戻り値はvendor/laravel/framework/src/Illuminate/Auth/SessionGuard.phpです
Auth::guard()は/sample/config/auth.phpの記述に対応したguardを返します。
auth.phpのdefaults->guardの値がwebなので、auth.phpのguards->web->driverの値を取り、それがsessionなので、SessionGuardを返します。SessionGuardの$this->providerには/sample/vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.phpが入っています。これもauth.phpで設定しているためです。auth.phpのproviders->users->driverがeloquentだからです
EloquentUserProviderの$this->modelにはApp\Models\Userが入っています。これもauth.phpで設定しているためです。auth.phpのproviders->users->modelがApp\Models\User::classだからです

・event
RegistersUsersでevent()が実行されています。event関数は与えられた引数のクラス名をキーにして、app/Providers/EventServiceProvider.phpの$listenから値を取得し、その値のクラスのhandleメソッドを実行します

・ログインの時に使う認証項目
デフォルトではログインの時、E-Mail AddressとPasswordを入力することになっていますが、入力項目をE-Mail Addressでないものにすることができます。なぜE-Mail AddressになっているかというとLoginController.phpで使っているトレイトvendor/laravel/ui/auth-backend/AuthenticatesUsers.php内のusername()関数が'email'を返しているからです。LoginControllerでusernameメソッドを定義しusersテーブルの別のカラムを返すようにすれば、emailではない項目を認証に使用できるようになります

・ユーザー登録の時に使う項目
ユーザー登録時の入力項目はデフォルトではname、email、passwordですが、もっと項目を増やしたい場合、tableにカラム追加し、viewにも項目を増やし、RegisterControllerのvalidatorメソッドとcreateに増やした項目の処理を追記し、App\Models\Userの$fillableにも増やした項目を追加します

・ログイン認証回数制限
ログイン認証を何回試みることを許可するか。その回数失敗したら何分間ログインできなくするかを設定できます
LoginControllerにmaxAttemptsとdecayMinutesというプロパティを定義します
// 最大ログイン認証回数
protected $maxAttempts = 5;
// $maxAttempts回ログイン失敗したら何分ログインできなくするか
protected $decayMinutes= 1;
これらはThrottlesLoginsというトレイトで使われています。
(コントローラー)app/Http/Controllers/Auth/LoginController.php->(トレイト)vendor/laravel/ui/auth-backend/AuthenticatesUsers.php->(トレイト)vendor/laravel/ui/auth-backend/ThrottlesLogins.php
maxAttempts()関数とdecayMinutes()関数が定義されています。そこで使われます。プロパティを定義しなかった場合、デフォルトで5回、ロック1分になっていることもわかります
また、hasTooManyLoginAttemptsが認証失敗制限回数になったか判定するメソッド、sendLockoutResponseがロックがかかったことを知らせるレスポンスを返すメソッドです

(3) viewの確認
/sample/resources/views/auth配下にviewは格納されています
説明が必要な難しい内容にはなっていません
画面の見た目は必ず変えると思います
/sample/resources/views/auth配下のbladeファイルを好きなように変更してください

Authファサード

Authファサードという認証ユーザーに関する便利メソッドを利用できます
use Illuminate\Support\Facades\Auth;
// 現在認証されているユーザーの取得
$user = Auth::user();
if (Auth::check()) {
// ユーザーはログインしている
}
上記のように簡単に認証済みユーザーを取得できたり、ログイン済みかどうか判定できます
このAuthファサードですが、Authファサード実行時呼ばれるのは、vendor/laravel/framework/src/Illuminate/Auth/AuthManager.phpです。このAuthManagerにメソッドが定義されていればAuthManagerのメソッドが呼ばれ、AuthManagerに定義されていないメソッドであれば、guardのメソッドが呼ばれます
Auth::user()ならAuthManagerにuserというメソッドは無いので、SessionGuardのuserメソッドが呼ばれます。Auth::check()ならAuthManagerにcheckというメソッドは無いので、SessionGuardのcheckメソッドが呼ばれています(SessionGuardのcheckメソッドは、SessionGuardで使われているGuardHelpersトレイトで実装されてます)
Auth::guard()なら、AuthManagerに定義されているのでAuthManagerのguardメソッドが呼ばれます
AuthManager
SessionGuard

ユーザー登録時のメールアドレス確認

ユーザー登録時に入力されたメールアドレス宛に実際にメールを送信し、そのメールに記載されているリンクをクリックしてもらい、メールアドレス確認をするように改修します

SMTPサーバーの設定をしてない方は下記記事を参考に事前にしておいてください
Laravelでメール送信する

メール送信される流れは下記です
ユーザー登録時
vendor/laravel/ui/auth-backend/RegistersUsers.phpのregisterメソッド内で
event(new Registered($user = $this->create($request->all())));
が呼ばれ、app/Providers/EventServiceProvider.phpによって登録されている
SendEmailVerificationNotificationクラスのhandleメソッドが実行され
app/Models/User.phpのsendEmailVerificationNotificationメソッドが呼ばれます
これでメールが送信されます
User.phpのsendEmailVerificationNotificationメソッドで呼んでいる$this->notifyはメール送信を実行するメソッドです。notifyメソッド定義場所は下記です
User.php->(トレイト)vendor/laravel/framework/src/Illuminate/Notifications/Notifiable.php->(トレイト)vendor/laravel/framework/src/Illuminate/Notifications/RoutesNotifications.php
$this->notifyの中では
vendor/laravel/framework/src/Illuminate/Notifications/ChannelManager.phpのsendを実行してメール送信しています

ではユーザー登録時メール送信するために必要なものを作っていきます

(1) メール本文の作成
/sample/resources/views/sample/registerUser.blade.phpファイル作成

registerUser.blade.php
<html>
    <body>
        <a href="{{$url}}">メールアドレスの確認</a>
    </body>
</html>

(2) 通知クラスの作成
/sample/app/Notificationsフォルダ作成
/sample/app/Notifications/RegisterUser.phpファイル作成

RegisterUser.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Auth\Notifications\VerifyEmail;

class RegisterUser extends VerifyEmail
{
    use Queueable;

    public function toMail($notifiable)
    {
        $verificationUrl = $this->verificationUrl($notifiable);

        return (new MailMessage)
                ->subject('ユーザー登録')
                ->view('sample.registerUser', ['url' => $verificationUrl]);

    }

}

(3) Modelの修正
/sample/app/Models/User.php修正

User.php
‥‥
use App\Notifications\RegisterUser;
‥‥
class User extends Authenticatable implements MustVerifyEmail
‥‥
    public function sendEmailVerificationNotification()
    {
        $this->notify(new RegisterUser());
    }
‥‥

use文追記
implements MustVerifyEmail追記
sendPasswordResetNotificationメソッド追加
これでvendor/laravel/framework/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.phpのhandleメソッド内のif文がtrueになります

(4) ルーティング修正
/sample/routes/web.php修正

‥
/* Auth::routes(); */ 
Auth::routes(['verify' => true]);
‥

Auth::routes()に引数['verify' => true]を渡す
これによって、vendor/laravel/ui/src/AuthRouteMethods.phpのauthメソッド内if ($options['verify'] ?? false)がtrueになり、emailVerificationメソッド内のルーティングが有効になります

動作確認その2

http://localhost/laravelSample/
画面右上のREGISTERをクリックし、Name、E-Mail Address、Password、Confirm Passwordを入力してRegisterボタンをクリック
入力したE-Mail Address充てにメールが送信されました
そのメールにあるリンクをクリックします
MySQLでlaravel_sampleデータベースを確認してみましょう
select * from users;
email_verified_atカラムにクリックした時刻が入っています

パスワードリセットの実装

ユーザーがパスワードを忘れた場合のパスワードリセットを実装します

パスワードリセット希望時にはメール送信が行われ、そのメールに記載されているリンクからパスワード再設定画面に遷移します

メール送信される流れは下記です
パスワードリセット画面でSend Password Reset Linkボタンをクリック時
vendor/laravel/ui/auth-backend/SendsPasswordResetEmails.phpのsendResetLinkEmailメソッド内の$this->broker()でvendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.phpを取得し、PasswordBrokerのsendResetLinkを実行します
PasswordBrokerのsendResetLink内で
app/Models/User.phpのsendPasswordResetNotificationメソッドが呼ばれます
これでメールが送信されます

ではそれを実行するために必要なものを作っていきます

(1) password_resetsテーブルの作成
先ほどphp artisan ui vue --authをしたときに
/sample/database/migrations/xxxx_xx_xx_xxxxxx_create_password_resets_table.php
ができています
これをデータベースに流し込みます

コマンドラインで
cd sample
php artisan migrate
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します

MySQLでlaravel_sampleデータベースを確認してみましょう
desc password_resets;
password_resetsテーブルができました

(2) メール本文の作成
/sample/resources/views/sample/resetPassword.blade.phpファイル作成

resetPassword.blade.php
<html>
    <body>
        <a href="{{$url}}">パスワードリセット</a>
        <div>このリンクは{{$limit}}分後に期限切れになります</div>
    </body>
</html>

(2) 通知クラスの作成
/sample/app/Notifications/ResetPassword.phpファイル作成

ResetPassword.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class ResetPassword extends Notification
{
    use Queueable;

    public $token;

    public function __construct($token)
    {
        $this->token = $token;
    }

    public function via($notifiable)
    {
        return ['mail'];
    }

    public function toMail($notifiable)
    {
        $url = url(route('password.reset', [
            'token' => $this->token,
            'email' => $notifiable->getEmailForPasswordReset(),
        ], false));

        return (new MailMessage)
                ->subject('パスワードリセット')
                ->view('sample.resetPassword', ['url' => $url, 'limit' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]);

    }

    public function toArray($notifiable)
    {
        return [];
    }
}

(3) Modelの修正
/sample/app/Models/User.php修正

User.php
‥‥
use App\Notifications\ResetPassword;
‥‥
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new ResetPassword($token));
    }
‥‥

use文追記
sendPasswordResetNotificationメソッド追加

動作確認その3

http://localhost/laravelSample/
画面右上のLOGINをクリックし、Forgot Your Password?リンクをクリック
E-Mail Addressを入力し、Send Password Reset Linkボタンをクリック
入力したE-Mail Address充てにメールが送信されました
そのメールにあるリンクをクリックします
Passwordを再設定する画面に遷移します

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3