Détails de mise en œuvre du système d'authentification des utilisateurs Laravel

不言
Libérer: 2023-04-02 16:56:01
original
2257 Les gens l'ont consulté

Cet article présente principalement les détails de mise en œuvre du système d'authentification des utilisateurs Laravel, qui a une certaine valeur de référence. Maintenant, je le partage avec tout le monde. Les amis dans le besoin peuvent s'y référer

Détails de mise en œuvre du système d'authentification des utilisateurs

Dans la section précédente, nous avons présenté les connaissances de base du système Laravel Auth et parlé de ses composants principaux. Dans cette section, nous nous concentrerons sur les détails de mise en œuvre du système Laravel Auth, en nous concentrant principalement sur

cela. c'est, AuthC'est comment charger le garde d'authentification (Guard) et le fournisseur d'utilisateurs (UserProvider) ainsi que les détails d'implémentation de l'enregistrement et de la connexion des utilisateurs par défaut En triant ces détails d'implémentation, nous pouvons également savoir comment personnaliser l'authentification Auth. pour répondre à nos propres projets Exigences d'authentification des utilisateurs. AuthManager

Chargement de l'observateur et du fournisseur d'utilisateurs via AuthManager

AuthManager utilise de nombreuses méthodes pour charger l'observateur et le fournisseur d'utilisateurs, et la description en mots n'est pas claire. Nous utilisons des annotations dans cette méthode de processus pour voir. les détails spécifiques de mise en œuvre.

namespace Illuminate\Auth;

class AuthManager implements FactoryContract
{
    /**
     * 尝试从$guards属性中获取指定的Guard
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
     */
    public function guard($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

        return isset($this->guards[$name])
                    ? $this->guards[$name]
                    : $this->guards[$name] = $this->resolve($name);
    }
    
    /**
     * 解析出给定name的Guard
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
     *
     * @throws \InvalidArgumentException
     */
    protected function resolve($name)
    {
        //获取Guard的配置
        //$config = ['driver' => 'session', 'provider' => 'users']
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
        }
       //如果通过extend方法为guard定义了驱动器,这里去调用自定义的Guard驱动器
        if (isset($this->customCreators[$config['driver']])) {
            return $this->callCustomCreator($name, $config);
        }
        //Laravel auth默认的配置这里是执行createSessionDriver
        $driverMethod = 'create'.ucfirst($config['driver']).'Driver';

        if (method_exists($this, $driverMethod)) {
            return $this->{$driverMethod}($name, $config);
        }

        throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
    }
    
    /**
     * 从config/auth.php中获取给定名称的Guard的配置
     *
     * @param  string  $name
     * @return array
     */
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],
    protected function getConfig($name)
    {
        //'guards' => [
        //    'web' => [
        //        'driver' => 'session',
        //        'provider' => 'users',
        //    ],

        //    'api' => [
        //        'driver' => 'token',
        //        'provider' => 'users',
        //    ],
        //],
        // 根据Laravel默认的auth配置, 这个方法会获取key "web"对应的数组
        return $this->app['config']["auth.guards.{$name}"];
    }
    
    /**
     * 调用自定义的Guard驱动器
     *
     * @param  string  $name
     * @param  array  $config
     * @return mixed
     */
    protected function callCustomCreator($name, array $config)
    {
        return $this->customCreators[$config['driver']]($this->app, $name, $config);
    }
    
    /**
     * 注册一个自定义的闭包Guard 驱动器 到customCreators属性中
     *
     * @param  string  $driver
     * @param  \Closure  $callback
     * @return $this
     */
    public function extend($driver, Closure $callback)
    {
        $this->customCreators[$driver] = $callback;

        return $this;
    }
    
    /**
     * 注册一个自定义的用户提供器创建器到 customProviderCreators属性中
     *
     * @param  string  $name
     * @param  \Closure  $callback
     * @return $this
     */
    public function provider($name, Closure $callback)
    {
        $this->customProviderCreators[$name] = $callback;

        return $this;
    }
    
    /**
     * 创建基于session的认证看守器 SessionGuard
     *
     * @param  string  $name
     * @param  array  $config
     * @return \Illuminate\Auth\SessionGuard
     */
    public function createSessionDriver($name, $config)
    {
        //$config['provider'] == 'users'
        $provider = $this->createUserProvider($config['provider'] ?? null);

        $guard = new SessionGuard($name, $provider, $this->app['session.store']);

        if (method_exists($guard, 'setCookieJar')) {
            $guard->setCookieJar($this->app['cookie']);
        }

        if (method_exists($guard, 'setDispatcher')) {
            $guard->setDispatcher($this->app['events']);
        }

        if (method_exists($guard, 'setRequest')) {
            $guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
        }

        return $guard;
    }
    
    //创建Guard驱动依赖的用户提供器对象
    public function createUserProvider($provider = null)
    {
        if (is_null($config = $this->getProviderConfiguration($provider))) {
            return;
        }
        //如果通过Auth::provider方法注册了自定义的用户提供器creator闭包则去调用闭包获取用户提供器对象
        if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
            return call_user_func(
                $this->customProviderCreators[$driver], $this->app, $config
            );
        }

        switch ($driver) {
            case 'database':
                return $this->createDatabaseProvider($config);
            case 'eloquent':
                //通过默认的auth配置这里会返回EloquentUserProvider对象,它实现了Illuminate\Contracts\Auth 接口
                return $this->createEloquentProvider($config);
            default:
                throw new InvalidArgumentException(
                    "Authentication user provider [{$driver}] is not defined."
                );
        }
    }
    
    /**
     * 会通过__call去动态地调用AuthManager代理的Guard的用户认证相关方法
     * 根据默认配置,这里__call会去调用SessionGuard里的方法
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        return $this->guard()->{$method}(...$parameters);
    }
}
Copier après la connexion
Utilisateur enregistré

La voie d'enregistrement par défaut dans le système Laravel Auth est la suivante :

$this->post('register', 'Auth\RegisterController@register');
Copier après la connexion
La logique d'enregistrement de l'utilisateur est donc complétée par le registre méthode de RegisterController

class RegisterController extends Controller
{
    //方法定义在Illuminate\Foundation\Auth\RegisterUsers中
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        return $this->registered($request, $user)
        
     }
     
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
        ]);
    }
    
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }
         
}
Copier après la connexion
Le processus d'enregistrement est très simple. Il s'agit de vérifier que les données saisies par l'utilisateur sont correctes, puis d'écrire les données dans la base de données pour générer le cryptage du mot de passe utilisé par l'utilisateur. l'algorithme bcrypt. Si vous devez le remplacer par le sel couramment utilisé. La méthode de cryptage du mot de passe pour le cryptage du texte brut et le hachage peut modifier cette partie de la logique dans la méthode de création. Après avoir enregistré l'utilisateur, la méthode de connexion de SessionGuard sera appelée. pour charger les données utilisateur dans l'application. Notez que cette méthode de connexion n'a pas d'authentification de connexion, mais uniquement l'utilisateur authentifié est chargé dans l'application afin que nous puissions obtenir les données utilisateur via

n'importe où dans l'application. Auth::user()

Authentification de connexion utilisateur

La route de connexion du système Laravel Auth est la suivante

$this->post('login', 'Auth\LoginController@login');
Copier après la connexion
Jetons un coup d'œil à la logique de connexion dans LoginController

class LoginController extends Controller
{
    /**
     * 处理登录请求
     */
    public function login(Request $request)
    {
        //验证登录字段
        $this->validateLogin($request);
        //防止恶意的多次登录尝试
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }
        //进行登录认证
        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }
    
    //尝试进行登录认证
    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            $this->credentials($request), $request->filled('remember')
        );
    }
    
    //获取登录用的字段值
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }
}
Copier après la connexion
Vous pouvez voir Oui, la logique d'authentification de connexion est implémentée via la méthode

de SessionGuard, qui est en fait attempt. Jetons un coup d'œil à la logique de la méthode Auth::attempt() : <🎜. >attempt

class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
    public function attempt(array $credentials = [], $remember = false)
    {
        $this->fireAttemptEvent($credentials, $remember);

        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
       //如果登录认证通过,通过login方法将用户对象装载到应用里去
        if ($this->hasValidCredentials($user, $credentials)) {
            $this->login($user, $remember);

            return true;
        }
        //登录失败的话,可以触发事件通知用户有可疑的登录尝试(需要自己定义listener来实现)
        $this->fireFailedEvent($user, $credentials);

        return false;
    }
    
    protected function hasValidCredentials($user, $credentials)
    {
        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
    }
}
Copier après la connexion
La méthode

interroge d'abord les données utilisateur de la table utilisateur via le nom d'utilisateur via la méthode SessionGuard du fournisseur d'utilisateurs. Les informations utilisateur authentifiées sont implémentées via attempt. du fournisseur d'utilisateurs. L'implémentation de tous les fournisseurs d'utilisateurs Toutes les classes implémenteront les méthodes définies dans le contrat UserProvider (interface). Grâce à l'analyse ci-dessus, nous savons que le fournisseur d'utilisateurs par défaut est retriveBycredentialsvalidateCredentialsEloquentUserProvider<🎜. >La vérification du mot de passe de l'utilisateur dépend de

class EloquentUserProvider implements UserProvider
{
    从数据库中取出用户实例
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists(&#39;password&#39;, $credentials))) {
            return;
        }

        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, &#39;password&#39;)) {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }
    
    //通过给定用户认证数据来验证用户
    public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials[&#39;password&#39;];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }
}

class BcryptHasher implements HasherContract
{
    //通过bcrypt算法计算给定value的散列值
    public function make($value, array $options = [])
    {
        $hash = password_hash($value, PASSWORD_BCRYPT, [
            &#39;cost&#39; => $this->cost($options),
        ]);

        if ($hash === false) {
            throw new RuntimeException(&#39;Bcrypt hashing not supported.&#39;);
        }

        return $hash;
    }
    
    //验证散列值是否给定明文值通过bcrypt算法计算得到的
    public function check($value, $hashedValue, array $options = [])
    {
        if (strlen($hashedValue) === 0) {
            return false;
        }

        return password_verify($value, $hashedValue);
    }
}
Copier après la connexion
Elle est complétée par un hasher Le système d'authentification Laravel utilise l'algorithme bcrypt par défaut pour crypter le mot de passe en clair fourni par l'utilisateur puis le stocke dans la table user. Lors de la vérification, la méthode

du hachage EloquentUserProvider transmettra la méthode intégrée PHPhasherPour vérifier si le mot de passe en texte brut est la valeur d'origine du mot de passe en texte chiffré stocké. hasercheckAprès avoir trié les principaux détails du système d'authentification des utilisateurs, nous savons comment définir notre propre garde (Guard) ou fournisseur d'utilisateurs (UserProvider). Tout d'abord, ils doivent mettre en œuvre les méthodes dans le contrat qu'ils respectent chacun. avec. Connectez-vous de manière transparente au système d'authentification de Laravel, puis vous devez enregistrer votre propre garde ou fournisseur via les méthodes password_verify,

pour renvoyer la fermeture de l'instance de garde ou de fournisseur à Laravel, personnalisation de Guard et UserProvider. Il n'est pas nécessaire que ce soit un ensemble complet. Nous pouvons personnaliser le Guard séparément tout en utilisant le EloquentUserProvider par défaut, ou laisser le SessionGuard par défaut utiliser un UserProvider personnalisé.

Auth::extendDans la section suivante, je donnerai un cas utilisé dans notre précédent développement de projet pour mieux expliquer comment étendre le système Laravel Auth. Auth::provider

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

L'applet Laravel WeChat obtient les détails de l'utilisateur et analyse l'expansion du code de l'applet avec des paramètres


Avantages de l'utilisation Conteneur de services Laravel

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!