zoukankan      html  css  js  c++  java
  • Laravel 源码解读系列第四篇-Auth 机制

    前言

    Laravel有一个神器:

    php artisan make:auth
    

    能够快速的帮我们完成一套注册和登录的认证机制,但是这套机制具体的是怎么跑起来的呢?我们不妨来一起看看他的源码。不过在这篇文章中,我只会阐述大致的流程,至于一些具体的细节,比如他的登录次数限制是怎么完成的之类的不妨自己去寻找答案。
    源码解读系列,有兴趣的小伙伴可以点个star,我会持续更新各个部分的解读,也是和大家一起进步的一个过程,如有写的不对的地方还望指出。

    过程

    路由

    当我们执行完命令之后,我们会发现,在routes/web.php中多了这样一行代码:

    Auth::routes();
    

    结合我们在前面讲到的Facades,我们会执行Facades/Auth.phproutes方法:

    public static function routes()
        {
            static::$app->make('router')->auth();
        }
    

    $app->make('router')会返回一个Routing/Router.php对象的实例,而他的auth方法是:

    public function auth()
        {
            // Authentication Routes...
            $this->get('login', 'AuthLoginController@showLoginForm')->name('login');
            $this->post('login', 'AuthLoginController@login');
            $this->post('logout', 'AuthLoginController@logout')->name('logout');
    
            // Registration Routes...
            $this->get('register', 'AuthRegisterController@showRegistrationForm')->name('register');
            $this->post('register', 'AuthRegisterController@register');
    
            // Password Reset Routes...
            $this->get('password/reset', 'AuthForgotPasswordController@showLinkRequestForm')->name('password.request');
            $this->post('password/email', 'AuthForgotPasswordController@sendResetLinkEmail')->name('password.email');
            $this->get('password/reset/{token}', 'AuthResetPasswordController@showResetForm')->name('password.reset');
            $this->post('password/reset', 'AuthResetPasswordController@reset');
        }
    

    而这里的getpost方法,其实也就是我们通过Route::get等最终会调用的方法。

    注册

    我们直接看表单提交的方法:

            $this->post('register', 'AuthRegisterController@register');
    
    //RegisterController.php
    class RegisterController extends Controller
    {
        /*
        |--------------------------------------------------------------------------
        | Register Controller
        |--------------------------------------------------------------------------
        |
        | This controller handles the registration of new users as well as their
        | validation and creation. By default this controller uses a trait to
        | provide this functionality without requiring any additional code.
        |
        */
    
        use RegistersUsers;
    
        /**
         * Where to redirect users after registration.
         *
         * @var string
         */
        protected $redirectTo = '/home';
    
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('guest');
        }
    
        /**
         * Get a validator for an incoming registration request.
         *
         * @param  array  $data
         * @return IlluminateContractsValidationValidator
         */
        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',
            ]);
        }
    
        /**
         * Create a new user instance after a valid registration.
         *
         * @param  array  $data
         * @return User
         */
        protected function create(array $data)
        {
            return User::create([
                'name' => $data['name'],
                'email' => $data['email'],
                'password' => bcrypt($data['password']),
            ]);
        }
    }
    

    里面使用到了RegistersUsers这个trait,里面就有我们需要的register方法:

    public function register(Request $request)
        {
            $this->validator($request->all())->validate();
    
            event(new Registered($user = $this->create($request->all())));
    
    //        默认情况下,$this->guard()会返回一个`SessionGuard`的对象
            $this->guard()->login($user);
    
            return $this->registered($request, $user)
                            ?: redirect($this->redirectPath());
        }
    
        protected function guard()
        {
            return Auth::guard();
        }
    

    其中最核心的部分就是:

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

    $this->guard()在默认配置下会返回一个SessionGuard的对象,具体是这样实现的:

    前面我们有讲过,当我们执行Facades下一个不存在的方法时,我们会调用Facade.php__callStatic方法,这个方法会获取当前对象的getFacadeAccessor方法而返回一个对应的对象并调用他所需要调用的方法,这个详细过程在我的第三篇中都有所阐述。
    auth的别名绑定,是在我们初始化的过程中绑定的,具体可以看我写的第一篇,所以,这里我们会调用AuthManager这个对象:

     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'];
        }
    
    protected function resolve($name)
        {
            $config = $this->getConfig($name);
    
            if (is_null($config)) {
                throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
            }
    
            if (isset($this->customCreators[$config['driver']])) {
                return $this->callCustomCreator($name, $config);
            }
    
            $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
    
    'defaults' => [
            'guard' => 'web',
            'passwords' => 'users',
        ],
    
        'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
    
            'api' => [
                'driver' => 'token',
                'provider' => 'users',
            ],
        ],
    

    通过调用AuthManager可以拼接得出,最终他会调用一个createSessionDriver方法:

    public function createSessionDriver($name, $config)
        {
            $provider = $this->createUserProvider($config['provider']);
    
            $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;
        }
    

    所以最终是调用了SessionGuardlogin方法来完成session部分的功能。

    登录

    展示表单的部分就不赘述了,这里我们直接看:

    $this->post('login', 'AuthLoginController@login');
    
    //LoginController.php
    class LoginController extends Controller
    {
        use AuthenticatesUsers;
    
        /**
         * Where to redirect users after login.
         *
         * @var string
         */
        protected $redirectTo = '/home';
    
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('guest')->except('logout');
        }
    }
    

    他使用到了一个AuthenticatesUserstrait,里面有一个login方法,也就是我们要使用到的login了:

    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);
        }
    

    其实大部分和register的部分差不多,核心部分还是在于SessionGuard对象的获取,这里就不过多赘述了,不过值得一提的是,像Auth::check()等很多方法的使用,其实也会通过SessionGuard来完成,主要是通过:

    public function __call($method, $parameters)
        {
            return $this->guard()->{$method}(...$parameters);
        }
    
    public function check()
        {
            return ! is_null($this->user());
        }
    

    来得以完成调度。

  • 相关阅读:
    StartSSL免费证书申请笔记
    CAS实践笔录
    MySQL常用SQL/函数汇总(持续更新)
    Git学习笔记(持续更新)
    Nginx配置性能优化
    OneDrive无法正常登录
    Windows注册表(持续更新)
    Mysql操作笔记(持续更新)
    MySQL 绿色版(zip) 安装
    Ubuntu/Deepin下常用软件汇总(持续更新)
  • 原文地址:https://www.cnblogs.com/nineyang/p/7559991.html
Copyright © 2011-2022 走看看