如果你在使用Laravel的話,使用者的程式碼只需要一行程式碼就可以搞定
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// 驗證成功的邏輯
}
但是,如果你想切換為自定義的加密驗證方式,那麼這篇文章可能會給你一些思路
比如,如果我想把密碼的驗證方式更換為MD5,我應該怎麼做呢?
別急,先從laravel框架的驗證流程開始
我們呼叫的Auth::attempt()
在哪裡實現的呢?
先從Auth
找起
在config/app.php
中
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
// ...
]
我們看到我們呼叫Auth其實是呼叫了
Illuminate\Support\Facades\Auth::class
開啟這個類檔案
class Auth extends Facade
{
protected static function getFacadeAccessor()
{
return 'auth';
}
// ...
}
可以看到,Auth是透過Facade動態繫結的,繫結到哪裡呢,進一步尋找我們發現
在 vendor/laravel/framework/src/Illuminate/AuthServiceProvider
中
class AuthServiceProvider extends ServiceProvider
{
/**
* Register the authenticator services.
*
* @return void
*/
protected function registerAuthenticator()
{
$this->app->singleton('auth', function ($app) {
$app['auth.loaded'] = true;
return new AuthManager($app);
});
$this->app->singleton('auth.driver', function ($app) {
return $app['auth']->guard();
});
}
}
預設的Auth
繫結了AuthManager
,開啟AuthManager
檔案
<?php
namespace Illuminate\Auth;
use Closure;
use InvalidArgumentException;
use Illuminate\Contracts\Auth\Factory as FactoryContract;
class AuthManager implements FactoryContract
{
use CreatesUserProviders;
protected $app;
protected $guards = [];
public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return isset($this->guards[$name])
? $this->guards[$name]
: $this->guards[$name] = $this->resolve($name);
}
public function getDefaultDriver()
{
return $this->app['config']['auth.defaults.guard'];
}
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
}
並沒有找到attempt方法,不過有一個__call
的魔術方法,那肯定是他裡面沒錯了,為了快速找到他究竟是何方神聖,直接用
dd(get_class($this->guard()));
真正的attempt究竟被誰呼叫了呢?
列印了SessionGuard,繼續找下去
Illuminate\Auth\SessionGuard
開啟該類,發現終於發現了我們尋找好久的attempt的實現
class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
use GuardHelpers, Macroable;
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;
}
這就是我們一直使用的attempt
的實現,透過 $this->provider->retrieveByCredentials($credentials)
獲取使用者資訊,並驗證,如果成功則登入,並返回true
所以我們真正做的密碼驗證肯定在retrieveByCredentials
這個方法裡面
Laravel 預設提供了 UserProvider
為 EloquentUserProvider
開啟改方法
class EloquentUserProvider implements UserProvider
{
protected $hasher;
protected $model;
public function __construct(HasherContract $hasher, $model)
{
$this->model = $model;
$this->hasher = $hasher;
}
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
public function setHasher(HasherContract $hasher)
{
$this->hasher = $hasher;
return $this;
}
}
所以這裡的hasher就是系統預設的BcryptHasher了,我們修改他直接注入自己的haser
ok,瞭解思路了,開始搞它
1.編寫自己的hasher
<?php
namespace App\Helpers\Hasher;
use Illuminate\Contracts\Hashing\Hasher;
class MD5Hasher implements Hasher
{
public function check($value, $hashedValue, array $options = [])
{
return $this->make($value) === $hashedValue;
}
public function needsRehash($hashedValue, array $options = [])
{
return false;
}
public function make($value, array $options = [])
{
$value = env('SALT', '').$value;
return md5($value);
}
}
2.用自己的Hasher替換預設的Hasher
建立MD5HashServiceProvider
php artisan make:provider MD5HashServiceProvider
新增如下方法
<?php
namespace App\Providers;
use App\Helpers\Hasher\MD5Hasher;
use Illuminate\Support\ServiceProvider;
class MD5HashServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->app->singleton('hash', function () {
return new MD5Hasher;
});
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
//
}
public function provides()
{
return ['hash'];
}
}
然後在config/app.php
的providers
中,將
Illuminate\Hashing\HashServiceProvider::class,
替換為
\App\Providers\MD5HashServiceProvider::class,
OK,大功告成
本作品採用《CC 協議》,轉載必須註明作者和本文連結