在Laravel 5.1中添加自定义认证驱动程序
本答案最适用于Laravel 5.1。如果您使用其他版本,请小心。请注意,我认为这是Laravel中相当高级的水平,因此如果您不完全了解自己在做什么,可能会导致应用程序崩溃。该解决方案并非端到端正确。这只是一个通用指南,告诉您需要做什么才能使其正常工作。
提示:有关此主题的Laravel文档在此处。
提示2:您提到的最后一个链接在我看来非常有用。阅读该链接后,我学到了所有这些知识。
http://laravel.io/forum/11-04-2014-laravel-5-how-do-i-create-a-custom-auth-in-laravel-5
在开始之前,我想先描述一下登录流程,这将有助于您了解该过程。Laravel使用一个
driver
来连接数据库以获取您的记录。 Laravel预装了两个驱动程序 -
eloquent
和
database
。我们想创建第三个驱动程序,以便我们可以根据需要进行自定义。
您的vendor文件夹中的
Illuminate\Auth\Guard
是主要文件,其中包含用户登录和注销的代码。此文件主要使用两个
Contracts(或接口)
,我们需要覆盖这些接口才能使我们的驱动程序正常工作。从Laravel的文档中阅读以下内容:
“Illuminate\Contracts\Auth\UserProvider实现仅负责从持久存储系统(例如MySQL,Riak等)中提取Illuminate\Contracts\Auth\Authenticatable实现。这两个接口允许Laravel身份验证机制继续运行,而不管用户数据存储在哪里或使用什么类型的类来表示它。”
因此,我们的驱动程序需要实现
Illuminate\Contracts\Auth\UserProvider
和
Illuminate\Contracts\Auth\Authenticatable
,并告诉Laravel使用这些实现而不是默认值。
好的,让我们开始吧。
步骤1:
为您的驱动程序选择一个名称。我将我的命名为
socialite
。然后在您的
config/auth.php
文件中,将
driver
的名称更改为
socialite
。通过这样做,我们刚告诉Laravel使用此驱动程序进行身份验证,而不是默认的
eloquent
。
步骤2:
在您的
app/Provider/AuthServiceProvider
文件的
boot()
方法中添加以下行:
Auth::extend('socialite', function($app) {
$provider = new SocialiteUserProvider();
return new AuthService($provider, App::make('session.store'));
});
我们在这里所做的是:
- 我们首先使用
Auth
门面来定义 socialite
驱动程序。
SocialiteUserProvider
是 UserProvider
的一个实现。
AuthService
是我对 Guard
类的扩展。该类构造函数的第二个参数是会话,Laravel 使用它来获取和设置会话。
- 因此,我们基本上告诉 Laravel 使用我们自己的
Guard
类实现而不是默认的实现。
步骤 3:
创建 SocialiteUserProvider
。如果您阅读 Laravel 的文档,您将理解每个方法应该返回什么。我已经创建了第一个方法作为示例。正如您所看到的,我使用我的 UserService
类来获取结果。您可以以任何想要的方式获取您自己的结果。然后我创建了一个 User
对象。这个 User
类实现了 Illuminate\Contracts\Auth\Authenticatable
契约。
<?php
namespace App\Extensions;
use App\User;
use App\Services\UserService;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
class SocialiteUserProvider implements UserProvider
{
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function retrieveById($identifier)
{
$result = $this->userService->getUserByEmail($identifier);
if(count($result) === 0)
{
$user = null;
}
else
{
$user = new User($result[0]);
}
return $user;
}
public function retrieveByToken($identifier, $token)
{
}
public function updateRememberToken(Authenticatable $user, $token)
{
}
public function retrieveByCredentials(array $credentials)
{
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
}
}
步骤4:
创建一个实现了Authenticatable接口的User类。这个类必须实现该接口,因为Guard类将使用此类来获取值。
<?php
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
class User implements Authenticatable
{
protected $primaryKey = 'userEmail';
protected $attributes = [];
public function __construct(array $attributes)
{
$this->attributes = $attributes;
}
public function getUserAttributes()
{
return $this->attributes;
}
public function getAuthIdentifier()
{
return $this->attributes[$this->primaryKey];
}
public function getAuthPassword()
{
}
public function getRememberToken()
{
}
public function setRememberToken($value)
{
}
public function getRememberTokenName()
{
}
}
步骤5:
最后创建AuthService类,调用Guard方法。这是我的实现方式,你可以根据自己的需要编写自己的实现方式。我们在这里扩展了Guard类来实现两个新函数,它们都很容易理解。
<?php
namespace App\Services;
use Illuminate\Auth\Guard;
class AuthService extends Guard
{
public function signin($email)
{
$credentials = array('email' => $email);
$this->fireAttemptEvent($credentials, false, true);
$this->lastAttempted = $user = $this->provider->retrieveById($email);
if($user !== null)
{
$this->login($user, false);
return true;
}
else
{
return false;
}
}
public function signout()
{
$this->clearUserDataFromStorage();
if(isset($this->events))
{
$this->events->fire('auth.logout', [$this->user()]);
}
$this->user = null;
$this->loggedOut = true;
}
}
第六步:奖励步骤
为了完整回答问题,我还将解释UserService
类所期望的结构。首先让我们了解一下这个类的作用。在上面的步骤中,我们创建了一切,让laravel知道如何使用我们的身份验证驱动程序,而不是他们的。但我们仍然没有告诉laravel如何获取数据。我们只告诉laravel,如果您调用userService->getUserByEmail($email)
方法,您将获得您的数据。因此,现在我们只需实现此函数即可。
例如1:您正在使用Eloquent
。
public function getUserByEmail($email)
{
return UserModel::where('email', $email)->get();
}
例如2:您正在使用Fluent
。
public function getUserByEmail($email)
{
return DB::table('myusertable')->where('email', '=', $email)->get();
}
更新:2016年6月19日
感谢@skittles指出我没有清楚地显示文件应该放在哪里。所有的文件都应按照给定的命名空间放置。例如,如果命名空间是App\Extensions
,类名是SocialiteUserProvider
,那么文件的位置就是App\Extensions\SocialiteUserProvider.php
。在laravel中,App
目录是app
文件夹。