Laravel 获取当前 Guard 分析 —源自电商购物车的实际需求
2018-03-29 00:00
218 查看
iBrand 产品中关于购物车的需求比较复杂,我们基于 overture/laravel-shopping-cart 扩展出了更加符合电商需求的购物车包,之前有文章进行过简单的介绍: Laravel shopping cart : 电商购物车包,线上完美运行中
源码地址:
ibrand/laravel-shopping-cart
用户登录后的购物车数据需要存储在数据库中。因为客户希望能够直观的看到目前购物车中商品信息,以便推送优惠信息来促使转化。虽然我们按照 GA 的标准把数据传送过去了,但是我们发现 GA中数据并不是非常准确。
用户在商城中的购物车数据
导购使用导购小程序代用户下单或结账时加入的购物车数据,不和用户购物车数据同步。
通过循环遍历目前所有的
用户门店扫码(二维码或条形码)自助下单的购物车数据要和商城的购物车数据区分
也就是现在存在三种购物车数据类型
用户在商城的购物车数据
用户在线下门店中自助下单的购物车数据
导购的购物车数据
追踪源码到
继续追踪源码到
到这里其实就结束了,我们发现
仍然看源码
代码最终到这里基本比较清楚了,已认证用户的请求会通过
设置已认证 guard 为默认 guard,代替
源码地址:
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' => [ 3ff0 '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\Requestclass 中
user()方法
public function user($guard = null) { return call_user_func($this->getUserResolver(), $guard); }
追踪源码到
Illuminate\Auth\AuthServiceProviderclass,具体执行的代码为:
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\AuthManagerclass
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); }
代码最终到这里基本比较清楚了,已认证用户的请求会通过
Authenticatemiddleware ,并且把系统默认的 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 值,可以直接通过AuthManagerclass 中的
getDefaultDriver()即可。
if ($defaultGuard = $app['auth']->getDefaultDriver()) { $currentGuard = $defaultGuard; $user = auth($currentGuard)->user(); }
相关文章推荐
- Laravel 获取当前 Guard 分析 —源自电商购物车的实际需求
- 对软件工程需求分析及创新项目等实际问题给提出建议或意见
- 通过距离感应器获取实际距离[FAQ04538][Sensor]java层获得P_sensor距离传感器当前真实值,不止0,1
- JS获取当前的日期时间 格式“yyyy-MM-dd HH:MM:SS” 可以根据需求修改
- js获取并分析当前网址的各个参数,非常有用!
- laravel 获取当前url, 路由
- 需求分析的实际故事
- 第104讲: Spark Streaming电商广告点击综合案例需求分析和技术架构
- java 获取当前日期 分析当前日期星期几
- 购物车分析与需求
- 对软件工程需求分析及创新项目等实际问题给提出建议
- Magento获取当前购物车产品总数量和总价格
- (转)Django ====> 实战学习篇二 需求分析及设计,创建第一个模型---购物车的应用
- 电商项目需求分析---七月实习总结
- (转)如何获取和分析非功能性需求
- 电商项目需求分析---七月实习总结
- 图解QQ空间日志爬虫的全部日志获取与日志实际地址分析.
- 获取应用程序当前所在实际路径
- 利用WebLog Experet分析日志获取性能需求
- 需求:需求获取技术之 文档分析