LoginSignup
6
6

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-07-11

tl;dr

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

(middleware作成への第一歩に向けて)

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

<?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 だった。

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)の2つ。

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

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だった。

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()$credentialspasswordが入って無ければ、与えられたkeyとvalue全部入れてユニークな値を取ってこようとしてるのに対し、Illuminate\Auth\EloquentUserProvider#validateCredentials()password固定!なんかひどくないかこれ・・。

結局

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

余談

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

6
6
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
6
6