返回
多商户用户权限设计方案详解 | Laravel实现
php
2024-12-31 03:23:22
多商户管理系统用户权限设计
针对多商户场景,每个商户需要独立的管理用户,并且具备超级管理员和普通管理员角色,如何高效实现?本篇文章将深入探讨此类用户权限系统的设计思路,并提供具体实现方案。
方案一:使用中间表管理商户用户
这种方案的核心思路是创建用户、商户和用户-商户关联三张表。通过中间表(比如 shop_user
表)存储用户和商户的对应关系,方便控制用户对特定商户的访问权限。
- 数据表设计
users
: 存储用户信息,包含id
、name
、email
、password
等通用字段。shops
: 存储商户信息,包含id
、name
、description
等字段。shop_user
: 存储用户与商户的关联关系,包含user_id
、shop_id
和role
三个字段。其中role
字段用于区分超级管理员和普通管理员,比如用 “super_admin” 和 “admin” 来表示。
- 逻辑流程
- 用户登录后,根据用户
id
查询shop_user
表,获取该用户关联的所有商户信息和角色。 - 前端页面可以选择当前操作的商户,根据用户选择的商户和用户角色来判断是否有操作该商户的权限。
- 任何需要验证权限的操作,都通过当前选定的商户和用户角色进行验证。
- 用户登录后,根据用户
代码示例(Laravel Eloquent 模型):
// App\Models\User.php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class User extends Authenticatable
{
public function shops(): BelongsToMany
{
return $this->belongsToMany(Shop::class, 'shop_user')->withPivot('role');
}
public function hasRoleInShop(Shop $shop, string $role): bool
{
return $this->shops()->where('shop_id', $shop->id)->where('role', $role)->exists();
}
}
// App\Models\Shop.php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Model;
class Shop extends Model
{
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class,'shop_user')->withPivot('role');
}
}
操作步骤:
- 创建相应的数据表结构。
- 定义 User 和 Shop 模型,以及模型间的关系,如上示例。
- 编写对应的 Controller 和 Middleware 进行权限验证。
比如可以通过用户登录后auth()->user()->shops()
来获取当前用户有权限访问的所有商铺,并在每次请求的时候进行角色判断。
例如auth()->user()->hasRoleInShop($shop, 'super_admin')
判断当前用户在该店铺是否为超级管理员。
安全建议:
- 确保密码加密存储,并使用安全的散列算法,避免存储明文密码。
- 对输入数据进行验证,防止 SQL 注入等攻击。
方案二:使用中间件结合权限包
此方案利用成熟的权限管理包,比如 Laravel-permission,在此基础上进行商户维度的扩展,配合自定义中间件实现精细化的权限控制。
- 权限包的选择 : 可以选择像 spatie/laravel-permission 这样广泛使用的权限管理包, 它能让你为每个用户分配角色和权限。
- 商户维度扩展 : 在原有角色权限基础上,结合店铺 id,细化每个用户在不同店铺的权限。
可以建立新的关系,或者对现有权限进行细化来达到目的,例如,创建一个 "super_admin.shop1", "admin.shop1", "super_admin.shop2"这样的角色来表达在不同商铺里的权限。 - 自定义中间件 : 针对每一个需要保护的路由,定义对应的中间件,判断用户是否拥有当前店铺、角色所需的权限。
代码示例 (Laravel中间件):
// App\Http\Middleware\ShopAccessMiddleware.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Spatie\Permission\Exceptions\UnauthorizedException;
class ShopAccessMiddleware
{
public function handle(Request $request, Closure $next, $role)
{
$shopId = $request->route('shop_id'); // 根据你的实际情况获取商户id
if (!$shopId){
throw UnauthorizedException::forPermissions([]);
}
$user = Auth::user();
if (!$user){
throw UnauthorizedException::forPermissions([]);
}
$hasPermission = $user->hasRole("{$role}.shop{$shopId}");
if (!$hasPermission){
throw UnauthorizedException::forPermissions([]);
}
return $next($request);
}
}
操作步骤:
- 安装 Laravel-permission 权限包 (composer require spatie/laravel-permission).
- 配置并发布
laravel-permission
权限包的数据迁移,进行数据迁移 (php artisan migrate
). - 在用户模型中,使用
Spatie\Permission\Traits\HasRoles;
这个trait, 以及定义角色,例如定义角色规则。例如 “super_admin.shop{shopId}”,”admin.shop{shopId}”。 - 编写自定义的ShopAccessMiddleware 中间件(如上面的示例)。
- 在路由文件中,对需要保护的路由使用对应的中间件, 传递角色参数,例如,
'middleware' => 'shopAccess:super_admin'
,这样在进行该路由时进行对应的权限校验,需要注意,需要在路由文件中使用商户的id信息来定义路由,/shop/{shop_id}/xxxxx
.
安全建议:
- 利用权限包提供的丰富的功能,例如角色和权限的管理。
- 合理使用中间件,确保路由的安全,不要随意给用户赋予过高的权限。
两种方案都可以满足需求,方案一比较轻量级,可以方便自定义。方案二使用现有权限包功能更为强大,适合复杂业务需求。根据项目的具体情况和团队的熟悉程度,可以选择最合适的方案。