4. 权限模型与RBAC设计:用户-角色-权限关系、资源与操作定义、Go结构体建模与数据库表设计
在构建权限审计网关时,权限模型是核心基石。本章采用业界成熟的基于角色的访问控制(RBAC)模型,将用户与权限解耦,通过角色作为中间层,实现灵活、可扩展的权限管理。我们将从概念模型、资源与操作定义、Go结构体建模到数据库表设计,逐层深入。
4.1 RBAC核心概念与关系
RBAC模型包含三个核心实体:用户(User)、角色(Role)、权限(Permission)。其核心思想是:权限不直接授予用户,而是授予角色;用户通过扮演角色获得权限。这种设计极大简化了权限管理,尤其适用于企业级多用户、多资源的系统。
4.2 资源与操作定义
权限的本质是对资源(Resource)执行操作(Action)的许可。在网关场景中,资源通常是API端点或服务,操作则是HTTP方法或自定义动作。
| 概念 | 说明 | 示例 |
|---|---|---|
| 资源 (Resource) | 被访问的对象,可以是API路径、服务名、数据实体 | /api/v1/orders、user-service、report:finance |
| 操作 (Action) | 对资源执行的动作,通常对应CRUD或自定义操作 | read、write、delete、export |
| 权限标识 (Permission Key) | 资源与操作的组合,唯一标识一个权限点 | order:read、user:write、report:export |
设计建议:权限标识采用
资源:操作 的命名规范,便于阅读和匹配。例如 order:read 表示“读取订单”权限。在网关层,通过解析请求的路径和方法,可以快速映射到对应的权限标识。
4.3 Go结构体建模
在Go语言中,我们使用结构体来映射RBAC实体。以下代码展示了核心模型的定义,包括字段标签、JSON序列化支持以及必要的关联关系。
// User 用户模型
type User struct {
ID uint `gorm:"primaryKey" json:"id"`
Username string `gorm:"uniqueIndex;size:64;not null" json:"username"`
Password string `gorm:"size:256;not null" json:"-"`
Email string `gorm:"size:128" json:"email"`
Status int `gorm:"default:1" json:"status"` // 1:启用 0:禁用
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// 关联角色(多对多)
Roles []Role `gorm:"many2many:user_roles;" json:"roles,omitempty"`
}
// Role 角色模型
type Role struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"uniqueIndex;size:64;not null" json:"name"`
Description string `gorm:"size:256" json:"description"`
IsSystem bool `gorm:"default:false" json:"is_system"` // 系统内置角色不可删除
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// 关联权限(多对多)
Permissions []Permission `gorm:"many2many:role_permissions;" json:"permissions,omitempty"`
}
// Permission 权限模型
type Permission struct {
ID uint `gorm:"primaryKey" json:"id"`
Resource string `gorm:"size:128;not null" json:"resource"` // 资源标识,如 "order"
Action string `gorm:"size:64;not null" json:"action"` // 操作标识,如 "read"
Description string `gorm:"size:256" json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// UserRole 用户-角色关联表(GORM自动处理many2many时可选显式定义)
type UserRole struct {
UserID uint `gorm:"primaryKey"`
RoleID uint `gorm:"primaryKey"`
}
// RolePermission 角色-权限关联表
type RolePermission struct {
RoleID uint `gorm:"primaryKey"`
PermissionID uint `gorm:"primaryKey"`
}
建模要点:
- 使用
gorm:"many2many:..."标签声明多对多关系,GORM会自动维护中间表。 - 密码字段标记为
json:"-",避免在JSON序列化时泄露敏感信息。 IsSystem字段用于保护系统内置角色,防止误删除。- 权限模型采用
Resource+Action组合,而非直接存储字符串标识,便于后续扩展和查询。
4.4 数据库表设计
基于Go结构体,我们设计对应的MySQL数据库表。以下是核心表的DDL语句,包含索引和约束。
-- 用户表
CREATE TABLE `users` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(64) NOT NULL COMMENT '用户名',
`password` VARCHAR(256) NOT NULL COMMENT '密码(加密后)',
`email` VARCHAR(128) DEFAULT '' COMMENT '邮箱',
`status` TINYINT DEFAULT 1 COMMENT '状态: 1启用 0禁用',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 角色表
CREATE TABLE `roles` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64) NOT NULL COMMENT '角色名称',
`description` VARCHAR(256) DEFAULT '' COMMENT '角色描述',
`is_system` TINYINT(1) DEFAULT 0 COMMENT '是否系统内置',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_role_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
-- 权限表
CREATE TABLE `permissions` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`resource` VARCHAR(128) NOT NULL COMMENT '资源标识',
`action` VARCHAR(64) NOT NULL COMMENT '操作标识',
`description` VARCHAR(256) DEFAULT '' COMMENT '权限描述',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_resource_action` (`resource`, `action`),
INDEX `idx_resource` (`resource`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';
-- 用户-角色关联表
CREATE TABLE `user_roles` (
`user_id` BIGINT UNSIGNED NOT NULL,
`role_id` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`, `role_id`),
INDEX `idx_role_id` (`role_id`),
CONSTRAINT `fk_user_roles_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_user_roles_role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表';
-- 角色-权限关联表
CREATE TABLE `role_permissions` (
`role_id` BIGINT UNSIGNED NOT NULL,
`permission_id` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`role_id`, `permission_id`),
INDEX `idx_permission_id` (`permission_id`),
CONSTRAINT `fk_role_permissions_role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_role_permissions_permission` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限关联表';
性能与安全注意事项:
- 关联表使用复合主键
(user_id, role_id)和(role_id, permission_id),避免重复记录。 - 外键约束使用
ON DELETE CASCADE,删除用户或角色时自动清理关联关系,防止数据孤岛。 - 权限表的
(resource, action)联合唯一索引,确保同一个资源操作组合不会重复定义。 - 生产环境中建议对
user_roles和role_permissions表定期进行碎片整理,维持查询性能。
4.5 权限缓存策略预览
在网关层面,每次请求都查询数据库进行权限校验会带来较大延迟。因此,我们需要引入缓存层。下图展示了权限数据在缓存中的存储结构,为后续章节的缓存一致性方案奠定基础。