Laravel5.4のmake:auth再利用でハマった

# tl;dr

Laravel5.4でサクッと作れるユーザ認証機能をまるっと利用してGoogleApps認証に取り替えてみようと思い、ログイン状態をチェックする`Auth::attempt()`にpassword以外の列名で可否を確認しようとしたら、ハマった。

（middleware作成への第一歩に向けて）

# 公式ドキュメント：自前のユーザ認証

- see : https://readouble.com/laravel/5.4/ja/authentication.html

```php
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    /**
     * 認証を処理する
     *
     * @return Response
     */
    public function authenticate()
    {
        if (Auth::attempt(['email' => $email, 'password' => $password])) {
            // 認証に成功した
            return redirect()->intended('dashboard');
        }
    }
}
```
ここの、`Auth::attempt()`ってどこの実装から取ってきてるの？と思って探してみると、`Illuminate\Auth\AuthManager#createSessionDriver()`->`Illuminate\Auth\SessionGuard` だった。

```php:Illuminate\Auth\SessionGuard.php
    /**
     * Attempt to authenticate a user using the given credentials.
     *
     * @param  array  $credentials
     * @param  bool   $remember
     * @return bool
     */
    public function attempt(array $credentials = [], $remember = false)
    {
        $this->fireAttemptEvent($credentials, $remember);

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

        // If an implementation of UserInterface was returned, we'll ask the provider
        // to validate the user against the given credentials, and if they are in
        // fact valid we'll log the users into the application and return true.
        if ($this->hasValidCredentials($user, $credentials)) {
            $this->login($user, $remember);

            return true;
        }

        // If the authentication attempt fails we will fire an event so that the user
        // may be notified of any suspicious attempts to access their account from
        // an unrecognized user. A developer may listen to this event as needed.
        $this->fireFailedEvent($user, $credentials);

        return false;
    }
```

`fire*Event()`は脇においておくとして、気になるのは`$this->provider->retrieveByCredentials($credentials)`と`$this->hasValidCredentials($user, $credentials)`の２つ。

先に`$this->hasValidCredentials()`を紐解く。

```php:SessionGuard#hasValidCredentials()
    /**
     * Determine if the user matches the credentials.
     *
     * @param  mixed  $user
     * @param  array  $credentials
     * @return bool
     */
    protected function hasValidCredentials($user, $credentials)
    {
        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
    }
```

`$this->provider->validateCredentials($user, $credentials)`を呼んでる。これとさっきの`$this->provider->retrieveByCredentials($credentials)`と合わせて、`$this->provider`って誰なの？と探してみると、`Illuminate\Auth\EloquentUserProvider`だった。

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

    /**
     * Retrieve a user by the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials)) {
            return;
        }

        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.
        $query = $this->createModel()->newQuery();

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

        return $query->first();
    }

    /**
     * Validate a user against the given credentials.
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials['password'];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }
```
`Illuminate\Auth\EloquentUserProvider#retrieveByCredentials()`は`$credentials`に`password`が入って無ければ、与えられたkeyとvalue全部入れてユニークな値を取ってこようとしてるのに対し、`Illuminate\Auth\EloquentUserProvider#validateCredentials()`は`password`固定！なんかひどくないかこれ・・。

# 結局

列名をpasswordのまま再利用する事にした。

# 余談

大元の`Illuminate\Auth\AuthManager#createSessionDriver()`がどこから呼ばれてるのかサッパリ分からないんだけど、 http://qiita.com/washio12/items/59f5cde23b4205973c6b を読むと、何やらconfigから値を取って動的に組み立てて実行してるらしい。道理で全文検索してもヒットしないわけだね。