今天看啥
    热点:

      天发国际娱乐官网:  头发干枯脱落  充足的睡眠可以促进皮肤及毛发正常的新陈代谢,而代谢期主要在晚上特别是晚上10时到凌晨2时之间,这一段时间睡眠充足,就可以使得毛发正常新陈代谢。

      Laravel 获取当前 Guard 分析 —源自电商购物车的实际需求,laravel电商


      iBrand 产品中关于购物车的需求比较复杂,我们基于 overture/laravel-shopping-cart 扩展出了更加符合电商需求的购物车包,之前有文章进行过简单的介绍: Laravel shopping cart : 电商购物车包,线上完美运行中

      源码地址: ibrand/laravel-shopping-cart

      原需求

      最开始扩展这个包时是因为以下需求:

      • 用户登录后的购物车数据需要存储在数据库中。因为客户希望能够直观的看到目前购物车中商品信息,以便推送优惠信息来促使转化。虽然我们按照 GA 的标准把数据传送过去了,但是我们发现 GA中数据并不是非常准确。
      • 用户在商城中的购物车数据
      • 导购使用导购小程序代用户下单或结账时加入的购物车数据,不和用户购物车数据同步。

      原解决方案

      最初需求出来的时候,我们通过不同的 Guard 来作为用户购物车数据的区分,因为商城和导购是两种不同的用户系统,所以当时在购物车 ServiceProvider 中的代码如下:

                  $currentGuard = null;
                  $user = null;
                  $guards = array_keys(config('auth.guards'));
                  foreach ($guards as $guard) {
                      if ($user = auth($guard)->user()) {
                          $currentGuard = $guard;
                          break;
                      }
                  }
                  if ($user) {
                      //The cart name like `cart.{guard}.{user_id}`: cart.api.1
                      $cart->name($currentGuard.'.'.$user->id);
                  }else{
                      throw new Exception('Invalid auth.');
                  }

      通过循环遍历目前所有的 Guards 来获取目前请求中用户所属的 guard 值和用户对象,本来在新需求未增加时,一切都运行的挺正常。

      新需求

      18年新增的需求:

      • 用户门店扫码(二维码或条形码)自助下单的购物车数据要和商城的购物车数据区分

      也就是现在存在三种购物车数据类型

      • 用户在商城的购物车数据
      • 用户在线下门店中自助下单的购物车数据
      • 导购的购物车数据

      新需求解决方案

      新需求出现的时候,为了区分购物车数据,肯定是直接新建一个 guard,所以在 config/auth.php 中添加了 shop guard 代码如下。

      'guards' => [
              'web' => [
                  'driver' => 'session',
                  'provider' => 'users',
              ],
      
              'admin' => [
                  'driver' => 'session',
                  'provider' => 'admins',
              ],
      
              'api' => [
                  'driver' => 'passport',
                  'provider' => 'users',
              ],
      
              'shop' => [
                  'driver' => 'passport',
                  'provider' => 'users',
              ],
      
              'clerk' => [
                  'driver' => 'passport',
                  'provider' => 'clerk',
              ],
          ],

      问题产生

      本以为会运行良好,但是我们忽略了一个细节,api 和 shop 两个 guard 的 provider 是一样的,因为都是属于用户的,而 api 又定义在 shop 前面,所以当执行如下代码时会出现问题,因为循环到 auth('api')->user() 的时候就退出了,导致了 shop guard 的数据也会存储成 api guard.

                 foreach ($guards as $guard) {
                      if ($user = auth($guard)->user()) {
                          $currentGuard = $guard;
                          break;
                      }
                  }

      解决方案

      之前工程师未发现合适的方法,所以采用了循环遍历 guards 来判断当前请求已认证 guard,当新需求产生后,这个方法不再适用,但是又不能对当前的购物车包进行大改,所以只有再找解决办法,

      思路

      在 Laravel 中 request()->user() 都会获取到正确已认证的 guard user 数据,所以准备决定从这里的源码入手。

      源码分析

      request()->user() 实际调用的代码是 Illuminate\Http\Request class 中 user() 方法

          public function user($guard = null)
          {
              return call_user_func($this->getUserResolver(), $guard);
          }

      追踪源码到 Illuminate\Auth\AuthServiceProvider class,具体执行的代码为:return call_user_func($app['auth']->userResolver(), $guard);

          protected function registerRequestRebindHandler()
          {
              $this->app->rebinding('request', function ($app, $request) {
                  $request->setUserResolver(function ($guard = null) use ($app) {
                      return call_user_func($app['auth']->userResolver(), $guard);
                  });
              });
          }

      继续追踪源码到 Illuminate\Auth\AuthManager class

          public function shouldUse($name)
          {
              $name = $name ?: $this->getDefaultDriver();
      
              $this->setDefaultDriver($name);
      
              $this->userResolver = function ($name = null) {
                  return $this->guard($name)->user();
              };
          }

      到这里其实就结束了,我们发现 request()->user() 最终执行的代码是 $this->guard($name)->user() 。所以我们需要查看下shouldUser 方法是在哪里调用的。

      仍然看源码 Illuminate\Auth\Middleware\Authenticate:

          protected function authenticate(array $guards)
          {
              if (empty($guards)) {
                  return $this->auth->authenticate();
              }
      
              foreach ($guards as $guard) {
                  if ($this->auth->guard($guard)->check()) {
                      return $this->auth->shouldUse($guard);
                  }
              }
      
              throw new AuthenticationException('Unauthenticated.', $guards);
          }

      代码最终到这里基本比较清楚了,已认证用户的请求会通过 Authenticate middleware ,并且把系统默认的 guard 设置为当前请求的 guard.

      //获取到已认证用户的 guard
             foreach ($guards as $guard) {
                  if ($this->auth->guard($guard)->check()) {
                      return $this->auth->shouldUse($guard);
                  }
              }

      设置已认证 guard 为默认 guard,代替 config('auth.defaults.guard') 中的值

          public function shouldUse($name)
          {
              $name = $name ?: $this->getDefaultDriver();
      
              $this->setDefaultDriver($name);
      
              $this->userResolver = function ($name = null) {
                  return $this->guard($name)->user();
              };
          }

      最终方案

      所以获取到当前请求的 Guard 值,可以直接通过 AuthManager class 中的 getDefaultDriver() 即可。

       
      if ($defaultGuard = $app['auth']->getDefaultDriver()) {
         $currentGuard = $defaultGuard;
         $user = auth($currentGuard)->user();
      }

      www.1click-soft.comtruehttp://www.1click-soft.com/PHPjc/1316130.htmlTechArticleLaravel 获取当前 Guard 分析 —源自电商购物车的实际需求,laravel电商 iBrand 产品中关于购物车的需求比较复杂,我们基于overture/laravel-shoppi...

      相关文章

        暂无相关文章
      相关搜索:

      帮客评论

      视觉看点
      百度 360 搜狗