如何基于认证用户层级过滤仪表盘全量数据?
解决方案:同时兼容Eloquent与Query Builder的层级化区域数据过滤
针对你遇到的问题,推荐通过自定义Query Builder宏实现全局数据过滤,既能覆盖Eloquent模型又支持原生Query Builder,无需手动修改每个查询。以下是具体实现步骤:
1. 先在用户模型中封装权限判断逻辑
首先在User模型中添加获取用户允许访问区域的方法,根据层级返回对应区域ID数组:
// app/Models/User.php use App\Models\Region; class User extends Authenticatable { // ... 其他代码 // 判断是否为最高层级用户(如应用所有者) public function isTopLevel(): bool { // 根据你的层级规则实现,比如role_level >= 10代表最高级 return $this->role_level >= 10; } // 获取用户有权限访问的区域ID数组 public function getAllowedRegionIds(): array { if ($this->isTopLevel()) { // 最高层级用户返回所有区域ID return Region::pluck('id')->toArray(); } // 普通用户返回自身关联的区域ID return $this->regions->pluck('id')->toArray(); } }
2. 注册全局Query Builder宏
在AppServiceProvider的boot方法中注册自定义宏,让所有Query Builder实例(包括Eloquent生成的)都能调用过滤方法:
// app/Providers/AppServiceProvider.php use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\Auth; public function boot() { Builder::macro('filterByUserRegion', function ($regionColumn = 'region_id') { // 未登录用户直接返回空结果(可根据业务调整) if (!Auth::check()) { return $this->whereRaw('1=0'); } $user = Auth::user(); $allowedRegions = $user->getAllowedRegionIds(); // 无权限区域时返回空结果 if (empty($allowedRegions)) { return $this->whereRaw('1=0'); } // 最高层级用户跳过过滤 if ($user->isTopLevel()) { return $this; } // 普通用户添加区域过滤条件 return $this->whereIn($regionColumn, $allowedRegions); }); }
3. 全局使用过滤方法
不管是Eloquent模型还是原生Query Builder,都可以直接调用filterByUserRegion()方法实现自动过滤:
// Eloquent示例:获取当前用户有权限的订单 $orders = Order::filterByUserRegion()->get(); // Query Builder示例:获取当前用户有权限的员工数据 $employees = DB::table('employees')->filterByUserRegion('region_id')->get(); // 关联查询示例:指定关联表的区域列 $customerOrders = DB::table('orders') ->join('customers', 'orders.customer_id', '=', 'customers.id') ->filterByUserRegion('customers.region_id') ->select('orders.*') ->get();
额外优化建议
- 缓存区域权限:在
getAllowedRegionIds()中添加缓存,避免每次查询都重复获取区域数据:public function getAllowedRegionIds(): array { return cache()->remember("user_regions_{$this->id}", 3600, function () { if ($this->isTopLevel()) { return Region::pluck('id')->toArray(); } return $this->regions->pluck('id')->toArray(); }); } - 动态指定列名:如果不同表的区域列名不同,调用宏时可以传入自定义列名,比如
filterByUserRegion('office_region_id')。
内容的提问来源于stack exchange,提问作者Test Laravel
相关产品推荐
相关产品推荐

