添加自定义的 Guard
需要通过Auth门面的extend方法定义自己的认证guard,在App\Providers\AuthServiceProvider的boot方法中实现:
public function boot()
{
this->registerPolicies();
Auth::extend('XXX', function(app, name, arrayconfig) {
// 返回 Illuminate\Contracts\Auth\Guard 实例
guard = new XXXGuard(name,Auth::createUserProvider(config['provider']),this->app['session.store']);
//事件
if (method_exists(guard, 'setDispatcher')) {guard->setDispatcher(this->app['events']);
}
//请求
if (method_exists(guard, 'setRequest')) {
guard->setRequest(this->app->refresh('request', guard, 'setRequest'));
}
returnguard;
});
}
传递给 extend 方法的闭包回调需要返回 Illuminate\Contracts\Auth\Guard 的实现实例,该接口包含了自定义认证 guard 需要的一些方法:
<?php
namespace App\Services\Auth;
use Illuminate\Auth\Events\Authenticated;
use Illuminate\Auth\Events\Failed;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Attempting;
use Illuminate\Auth\Events\Logout;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Events\Dispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class XXXGuard implements Guard
{
use GuardHelpers;
protected session;
protectedname;
protected loggedOut = false;
protectedrequest;
protected events;
public function __construct(name,UserProvider provider,SessionInterfacesession,Request request = null)
{this->name = name;this->provider = provider;this->session = session;this->request = request;
}
/**
* Attempt to authenticate a user using the given credentials.
*
* @param arraycredentials
* @param bool remember
* @param boollogin
* @return bool
*/
public function attempt(array credentials = [],remember = false, login = true)
{this->fireAttemptEvent(credentials,remember, login);user = this->provider->retrieveByCredentials(credentials);
if (this->hasValidCredentials(user, credentials)) {
if (login) {
this->login(user, remember);
}
return true;
}
if (login) {
this->fireFailedEvent(user, credentials);
}
return false;
}
/**
* Determine if the user matches the credentials.
*
* @param mixeduser
* @param array credentials
* @return bool
*/
protected function hasValidCredentials(user, credentials)
{
return ! is_null(user) && this->provider->validateCredentials(user, credentials);
}
/**
* Log a user into the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatableuser
* @param bool remember
* @return void
*/
public function login(Authenticatableuser, remember = false)
{this->updateSession(user->getAuthIdentifier());
// If we have an event dispatcher instance set we will fire an event so that
// any listeners will hook into the authentication events and run actions
// based on the login and logout events fired from the guard instances.this->fireLoginEvent(user,remember);
this->setUser(user);
}
/**
* Update the session with the given ID.
*
* @param string id
* @return void
*/
protected function updateSession(id)
{
this->session->set(this->getName(), id);this->session->migrate(true);
}
/**
* Get a unique identifier for the auth session value.
*
* @return string
*/
public function getName()
{
return 'login_'.this->name.'_'.sha1(static::class);
}
/**
* Get the currently authenticated user.
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
if (this->loggedOut) {
return;
}
// If we've already retrieved the user for the current request we can just
// return it back immediately. We do not want to fetch the user data on
// every call to this method because that would be tremendously slow.
if (! is_null(this->user)) {
returnthis->user;
}
id =this->session->get(this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.user = null;
if (! is_null(id)) {
if (user = this->provider->retrieveById(id)) {
this->fireAuthenticatedEvent(user);
}
}
return this->user =user;
}
public function id()
{
if (this->loggedOut) {
return;
}
if (this->user()) {
return this->user()->getAuthIdentifier();
}
returnthis->session->get(this->getName());
}
/**
* Validate a user's credentials.
*
* @param arraycredentials
* @return bool
*/
public function validate(array credentials = [])
{
returnthis->attempt(credentials, false, false);
}
/**
* Fire the login event if the dispatcher is set.
*
* @param \Illuminate\Contracts\Auth\Authenticatableuser
* @param bool remember
* @return void
*/
protected function fireLoginEvent(user, remember = false)
{
if (isset(this->events)) {
this->events->fire(new Login(user, remember));
}
}
/**
* Fire the authenticated event if the dispatcher is set.
*
* @param \Illuminate\Contracts\Auth\Authenticatableuser
* @return void
*/
protected function fireAuthenticatedEvent(user)
{
if (isset(this->events)) {
this->events->fire(new Authenticated(user));
}
}
/**
* Fire the attempt event with the arguments.
*
* @param array credentials
* @param boolremember
* @param bool login
* @return void
*/
protected function fireAttemptEvent(arraycredentials, remember,login)
{
if (isset(this->events)) {this->events->fire(new Attempting(
credentials,remember, login
));
}
}
/**
* Fire the failed authentication attempt event with the given arguments.
*
* @param \Illuminate\Contracts\Auth\Authenticatable|nulluser
* @param array credentials
* @return void
*/
protected function fireFailedEvent(user, array credentials)
{
if (isset(this->events)) {
this->events->fire(new Failed(user, credentials));
}
}
/**
* Log the user out of the application.
*
* @return void
*/
public function logout()
{user = this->user();
// If we have an event dispatcher instance, we can fire off the logout event
// so any further processing can be done. This allows the developer to be
// listening for anytime a user signs out of this application manually.this->clearUserDataFromStorage();
if (isset(this->events)) {this->events->fire(new Logout(user));
}
// Once we have fired the logout event we will clear the users out of memory
// so they are no longer available as the user is no longer considered as
// being signed into this application and should not be available here.this->user = null;
this->loggedOut = true;
}
/**
* Remove the user data from the session and cookies.
*
* @return void
*/
protected function clearUserDataFromStorage()
{this->session->remove(this->getName());
}
/**
* Get the event dispatcher instance.
*
* @return \Illuminate\Contracts\Events\Dispatcher
*/
public function getDispatcher()
{
returnthis->events;
}
/**
* Set the event dispatcher instance.
*
* @param \Illuminate\Contracts\Events\Dispatcher events
* @return void
*/
public function setDispatcher(Dispatcherevents)
{
this->events =events;
}
/**
* Get the session store used by the guard.
*
* @return \Illuminate\Session\Store
*/
public function getSession()
{
return this->session;
}
/**
* Get the user provider used by the guard.
*
* @return \Illuminate\Contracts\Auth\UserProvider
*/
public function getProvider()
{
returnthis->provider;
}
/**
* Set the user provider used by the guard.
*
* @param \Illuminate\Contracts\Auth\UserProvider provider
* @return void
*/
public function setProvider(UserProviderprovider)
{
this->provider =provider;
}
/**
* Return the currently cached user.
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function getUser()
{
return this->user;
}
/**
* Set the current user.
*
* @param \Illuminate\Contracts\Auth\Authenticatableuser
* @return this
*/
public function setUser(Authenticatableuser)
{
this->user =user;
this->loggedOut = false;this->fireAuthenticatedEvent(user);
returnthis;
}
public function setRequest(Request request)
{this->request = request;
returnthis;
}
}
定义好自己的认证 guard 之后,可以在配置文件 auth.php 的 guards 配置中使用话这个 guard:
'guards' => [
'api' => [
'driver' => 'XXX',
'provider' => 'users',
],
],
添加自定义用户提供者
同样在App\Providers\AuthServiceProvider的boot方法中实现:
public function boot()
{
this->registerPolicies();
//
Auth::provider('YYY', function(app, array config) {
// 返回 Illuminate\Contracts\Auth\UserProvider实例
return new YYYProvider(config['model']);
});
}
定义提供者,返回Illuminate\Contracts\Auth\UserProvider的实现实例:
<?php
namespace App\Services\Auth;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Str;
class YYYProvider implements UserProvider
{
protected model;
public function __construct(model)
{
this->model =model;
}
public function createModel()
{
class = '\\'.ltrim(this->model, '\\');
return new class;
}
/**
* Retrieve a user by their unique identifier.
*
* @param mixedidentifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById(identifier)
{
returnthis->createModel()->newQuery()->find(identifier);
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* @param mixedidentifier
* @param string token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken(identifier, token)
{
//todo 根据token实现记住功能
return null;
}
/**
* Update the "remember me" token for the given user in storage.
*
* @param \Illuminate\Contracts\Auth\Authenticatableuser
* @param string token
* @return void
*/
public function updateRememberToken(Authenticatableuser, token)
{
//code
}
/**
* Retrieve a user by the given credentials.
*
* @param arraycredentials
* @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 askey => value) {
if (! Str::contains(key, 'password')) {
query->where(key, value);
}
}
returnquery->first();
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable user
* @param arraycredentials
* @return bool
*/
public function validateCredentials(Authenticatable user, arraycredentials)
{
plain =credentials['password'];
//具体验证密码有效性方法
return user->Password==md5(plain);
}
/**
* Gets the name of the Eloquent user model.
*
* @return string
*/
public function getModel()
{
return this->model;
}
/**
* Sets the name of the Eloquent user model.
*
* @param stringmodel
* @return this
*/
public function setModel(model)
{
this->model =model;
return $this;
}
}
之后可以在配置文件 config/auth.php 中切换到新的用户提供者
'providers' => [
'users' => [
'driver' => 'YYY',
],
],
然后,就可以在你的 guards 配置中使用这个提供者。