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
だった。
/**
* 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()
を紐解く。
/**
* 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
だった。
/**
* 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から値を取って動的に組み立てて実行してるらしい。道理で全文検索してもヒットしないわけだね。