Laravel 5.5 の認証機能とそのカスタマイズ

# Laravelの認証

Laravelにデフォルトで用意されている認証機能を使ってみました。
また、カスタマイズもやってみましたので、そのメモです。

# 参考リンク

- Laravel 5.5 認証 https://readouble.com/laravel/5.5/ja/authentication.html
- Laravel 5.5 API https://laravel.com/api/5.5/

# クイックスタート

まず新しくlaravelプロジェクトを作成します。
Laravel Installerが入っているなら以下のようなコマンド一行で作成できます。

```
laravel new auth-test
```

次に適当な空のデータベースを作成し、`.env`ファイルを適切に設定してください。ローカルならば以下の3つを設定すればだいたい動くと思います。

```
DB_DATABASE=データベース名
DB_USERNAME=データベースのユーザー名
DB_PASSWORD=データベースのパスワード
```

作成されたプロジェクトディレクトリの中で以下を実行します。

```
php artisan make:auth
php artisan migrate
php artisan serve
```

トップページ(例: http://localhost:8000/ )を開くと、右上に「LOGIN」「REGISTER」のメニューがあり、REGISTERを押してユーザー登録をするとトップページのメニューが「HOME」に変わります。

# 認証で使われるソースファイル

`make:auth`コマンドにより、以下のルートとビューが一括で作成されます。
コントローラー・モデル・マイグレーションファイルは最初から用意されています。

## 追加されたルート

`routes/web.php`に以下の一文が追加されます。

```php
Auth::routes();
```

これは`Auth`ファサードを通して`Illuminate\Routing\Router`インスタンスの`auth`メソッドを呼び出しています。これにより以下のルートが追加されます。

```php
// Authentication Routes...
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$this->post('logout', 'Auth\LoginController@logout')->name('logout');

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

// Password Reset Routes...
$this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
$this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
$this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
$this->post('password/reset', 'Auth\ResetPasswordController@reset');
```

上から、ログイン用・ユーザー登録用・パスワードリセット用のルートです。

## 追加されたビュー

`make:auth`コマンドにより`resources/views/auth`ディレクトリにいくつかビューファイルが追加されます。

- `login.blade.php` ログイン用のフォーム
- `register.blade.php` ユーザー登録用のフォーム
- `passwords/email.blade.php` パスワードリセット用のメール送信フォーム
- `passwords/reset.blade.php` パスワードリセット用の新パスワード登録フォーム

`resources/views/layouts/app.blade.php`に共通レイアウトも追加されます。

## コントローラー

`app/Http/Controllers/Auth`ディレクトリに認証用のコントローラーが最初から用意されています。

- `LoginController.php` ログインフォーム・ログイン・ログアウト
- `RegisterController.php` ユーザー登録フォーム・ユーザー登録
- `ForgotPasswordController.php` パスワードリセット用のメール送信フォーム・パスワードリセット用のメール送信
- `ResetPasswordController.php` パスワードリセット用の新パスワード登録フォーム・パスワードリセット用の新パスワード登録

## マイグレーション

`database/migrations`ディレクトリに最初から用意されています。

`***_create_users_table.php`がユーザーテーブル、
`***_create_password_resets_table.php`がパスワードリセット用のテーブルです。

## モデル

こちらも最初から`app/User.php`に用意されています。

# カスタマイズ

## ログイン後のリダイレクト先の変更

ログインすると`/home`へリダイレクトされますが、これをカスタマイズするには、`LoginController`、`RegisterController`、`ResetPasswordController`の`redirectTo`プロパティにリダイレクト先を定義します。

```php
protected $redirectTo = '/';
```

## ログイン対象のカラムの変更

デフォルトではemailカラムを認証に利用します。これを変更するには、テーブルに対象のカラムを追加し、ユーザー登録フォームとログインフォームをカスタマイズします。

例として`userid`カラムを認証に使う方法を以下に示します。

### テーブルにログイン対象カラムを追加する

まず、マイグレーションファイルを作成します。

```
php artisan make:migration update_users_table --table=users
```

作成された`***_update_users_table.php`の`up`メソッドに以下を追加すると`userid`カラムが追加されます。

```php
$table->string('userid')->unique()->after('email');
```

`down`メソッドも定義しておきましょう。

```php
$table->dropColumn('userid');
```

マイグレーションします。

```
php artisan migrate
```

### ユーザー登録フォームをカスタマイズする

次に、ユーザー登録フォームに入力欄を追加してみます。

`resources/views/auth/register.blade.php`の`name`欄をコピーして属性等を`userid`に変更して欄を増やします。

```php
<div class="form-group{{ $errors->has('userid') ? ' has-error' : '' }}">
    <label for="userid" class="col-md-4 control-label">User ID</label>

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

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

さらに、レコードを登録する部分である、`app/Http/Controllers/Auth/RegisterController.php`の`create`メソッドに`userid`を追加します。

```php
protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'userid' => $data['userid'], // 追加
        'password' => bcrypt($data['password']),
    ]);
}
```

もうひとつ設定しなければいけない箇所があります。モデルの`create`メソッドは、フォームなどからの予期せぬ一括代入を防ぐために、`$fillable`プロパティで代入できる項目を制限しています。

よって`app/User.php`の`$fillable`プロパティに`userid`を追加します。

```php
protected $fillable = [
    'name', 'email', 'userid', 'password',
];
```

これで登録ができるようになります。値のバリデーションが必要なら`app/Http/Controllers/Auth/RegisterController.php`の`validator`メソッドに追加します。

### ログインフォームをカスタマイズする

次に、ログインフォームをカスタマイズします。

`resources/views/auth/login.blade.php`の`email`欄を`userid`欄に変更します。

```php
<div class="form-group{{ $errors->has('userid') ? ' has-error' : '' }}">
    <label for="userid" class="col-md-4 control-label">User ID</label>

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

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

さらに、ログイン対象カラムを変更するために、`app/Http/Controllers/Auth/LoginController.php`で`username`メソッドを定義します。

```php
public function username()
{
    return 'userid';
}
```

これで`userid`と`password`でログインできるようになります。

## Userモデル以外を認証に使う

例えば`Staff`モデルを使う場合は`config/auth.php`を以下のように変更します。

```php
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Staff::class,
        ],
    ],
```

`Staff`モデルは`Model`クラスではなく`Authenticatable`クラスを継承する必要があります。
パスワードのカラムは最低60文字必要で、デフォルトの255文字が良いみたいです。
さらに自動ログインを使う場合は`remember_token`カラムも必要です。`rememberToken`メソッドを使ってマイグレーションするのが良いでしょう。