You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中3+表数据透视表实现:用户多组织多角色场景问询

嘿,这个多组织多角色的权限设计思路非常实用,刚好我在Laravel项目里也经常这么搞!我来帮你把这个方案从数据库到代码落地,一步步讲清楚~

一、数据库结构设计

你提到的三列联合约束表是这个场景的标准解法,我补全完整的SQL定义,并做了一点优化:

CREATE TABLE `organisation_role_user` (
    `organisation_id` int(10) unsigned NOT NULL,
    `role_id` int(10) unsigned NOT NULL,
    `user_id` int(10) unsigned NOT NULL,
    PRIMARY KEY (`organisation_id`, `role_id`, `user_id`), -- 用联合主键替代单独的唯一约束,兼顾性能
    FOREIGN KEY (`organisation_id`) REFERENCES `organisations`(`id`) ON DELETE CASCADE,
    FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE CASCADE,
    FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这里用联合主键的原因是:它既可以防止同一个用户在同一个组织下重复拥有同一个角色,还能提升关联查询的性能,比单独加UNIQUE(organisation_id, role_id, user_id)更高效。另外ON DELETE CASCADE配置能保证当组织、角色或用户被删除时,中间表的关联记录会自动清理,避免脏数据。

二、Laravel模型关联配置

接下来咱们把这个多对多关联映射到Laravel的模型里,三个核心模型的写法如下:

User模型

用户和组织、角色的关联需要指定中间表,并带上中间表的额外字段:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class User extends Authenticatable
{
    // 用户关联所属组织(附带角色信息)
    public function organisations(): BelongsToMany
    {
        return $this->belongsToMany(Organisation::class, 'organisation_role_user')
            ->withPivot('role_id') // 取出中间表的role_id字段
            ->using(OrganisationRoleUser::class); // 可选:自定义中间表模型时启用
    }

    // 用户关联拥有的角色(按组织分组)
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class, 'organisation_role_user')
            ->withPivot('organisation_id')
            ->using(OrganisationRoleUser::class);
    }
}

Organisation模型

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Organisation extends Model
{
    // 组织关联所有用户(附带用户在本组织的角色)
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'organisation_role_user')
            ->withPivot('role_id')
            ->using(OrganisationRoleUser::class);
    }

    // 组织关联所有被分配的角色
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class, 'organisation_role_user')
            ->withPivot('user_id')
            ->using(OrganisationRoleUser::class);
    }
}

Role模型

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Role extends Model
{
    // 角色关联所有拥有它的用户
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'organisation_role_user')
            ->withPivot('organisation_id')
            ->using(OrganisationRoleUser::class);
    }

    // 角色关联所有分配了它的组织
    public function organisations(): BelongsToMany
    {
        return $this->belongsToMany(Organisation::class, 'organisation_role_user')
            ->withPivot('user_id')
            ->using(OrganisationRoleUser::class);
    }
}

可选:自定义中间表模型

如果需要在中间表上添加额外的业务逻辑(比如快捷权限检查),可以创建一个继承自Pivot的模型:

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\Pivot;

class OrganisationRoleUser extends Pivot
{
    // 示例:检查该角色是否拥有某个权限
    public function hasPermission(string $permission): bool
    {
        return $this->role->permissions()->where('name', $permission)->exists();
    }
}
三、常用业务操作示例

给用户分配组织角色

// 给ID为1的用户,在ID为2的组织里分配ID为3的角色
$user = User::find(1);
$user->organisations()->attach(2, ['role_id' => 3]);

// 批量分配多个组织角色
$user->organisations()->attach([
    2 => ['role_id' => 3], // 组织2:角色3
    4 => ['role_id' => 5]  // 组织4:角色5
]);

验证用户在组织中的角色

// 检查用户是否在组织2中拥有角色3
$hasAdminRole = $user->organisations()
    ->where('organisations.id', 2)
    ->wherePivot('role_id', 3)
    ->exists();

// 获取用户在组织2中的所有角色
$rolesInOrg = $user->roles()
    ->wherePivot('organisation_id', 2)
    ->get();

处理用户当前组织

通常用户登录后需要选择当前操作的组织,咱们可以把选中的组织ID存在Session里:

// 存储当前操作的组织ID
session(['current_organisation_id' => 2]);

// 获取当前组织实例
$currentOrg = Organisation::find(session('current_organisation_id'));

// 获取用户在当前组织的角色
$currentRole = $user->roles()
    ->wherePivot('organisation_id', session('current_organisation_id'))
    ->first();
四、权限验证拓展

如果需要基于组织角色做细粒度权限控制,可以自定义Laravel Gate或者中间件:

// 在app/Providers/AuthServiceProvider.php的boot方法中定义Gate
Gate::define('manage-organisation', function (User $user, Organisation $organisation) {
    // 验证用户在该组织中是管理员或编辑(假设角色ID 1是管理员,2是编辑)
    return $user->organisations()
        ->where('organisations.id', $organisation->id)
        ->wherePivotIn('role_id', [1, 2])
        ->exists();
});

// 在控制器中使用验证
if (Gate::allows('manage-organisation', $organisation)) {
    // 执行组织管理操作
}

内容的提问来源于stack exchange,提问作者Hitunen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:48:57