laravel自定义用户认证

/ 0评 / 1

添加自定义的 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 配置中使用这个提供者。

完结

null