Laravel で認証パラメータを追加する

Laravel の認証は `php artisan make:auth` である程度のログイン機能が吐き出されて、あとはビューをちょちょいと変更したり Route 周りを自分の好みにカスタマイズしたりで非常に強力な認証が最小限の工数で利用できます。


しかしながら融通が効きにくいこともあり、例えばメールアドレス、パスワード以外の有効無効フラグを追加したいのだが、というときに公式ではこう記載されています。

```php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    /**
     * 認証を処理する
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return Response
     */
    public function authenticate(Request $request)
    {
        $credentials = $request->only('email', 'password');

        if (Auth::attempt($credentials)) {
            // 認証に成功した
            return redirect()->intended('dashboard');
        }
    }
}
```

```php
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
    // ユーザーは存在しており、かつアクティブで、資格停止されていない
}
```

しかし、`App\Http\Auth\LoginContoller.php` の実態たる `Illuminate\Foundation\Auth\AuthenticatesUsers` ではこんな記述はでてきません。
そこで[Laravel5.4のmake:auth再利用でハマった](https://qiita.com/positrium/items/361e8b8663d045681c93)を参考にしてどうすればフラグを認証判定に含めることができるかを調べてみました。


例のごとく結論を知りたい方は末尾へどうぞ。

ここでは有効・無効のフラグを `active` ではなく `is_valid` としています。



## 調査

参考元のサイトを踏まえて追って行くと、

Illuminate\Auth\SessionGuard.php の attempt メソッドにたどり着きます。

```php:Illuminate\Auth\SessionGuard.php

    public function attempt(array $credentials = [], $remember = false)
    {
        $this->fireAttemptEvent($credentials, $remember);

        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

        if ($this->hasValidCredentials($user, $credentials)) {
            $this->login($user, $remember);

            return true;
        }

        $this->fireFailedEvent($user, $credentials);

        return false;
    }

```

`retrieveByCredentials($credentials)` と `hasValidCredentials($user, $credentials)` の実体が `Illuminate\Auth\EloquentUserProvider.php` とのことなので確認。

```php:Illuminate\Auth\EloquentUserProvider.php

    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials))) {
            return;
        }

        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, 'password')) {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }


    public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials['password'];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }

```

retrieveByCredentials を確認すると、where でちゃんとパラメータが渡せるようになっていますね。
となると、key value 型の配列を $credentials に入れてあげれば良い。

$credentials が設定されているところは LoginController.php の継承元 `Illuminate\Foundation\Auth\AuthenticatesUsers` にあります。

```php:Illuminate\Foundation\Auth\AuthenticatesUsers.php

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }
```

$request->only　を var_dump してみると、


```php

array (size=2)
  'email' => string 'xxxxx@xxxxxx.xxxxx' (length=xx)
  'password' => string 'ABCDEFGH' (length=8)

```

という、素直な配列です。
ではコレに追加してやるだけですね。




## 結論


```php:App\Http\Auth\LoginContoller.php

use Illuminate\Http\Request;

protected function credentials(Request $request)
{
    $temporary = $request->only($this->username(), 'password');
    $temporary['is_valid'] = 1;

    return $temporary;
}
```

というわけで、is_valid は boolean 型ですので、1 なり true なりを渡してやるようにすれば、$credentials に追加することができ、DBの検索時 where に追加されるようになりました。