完善角色权限与数据隔离
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
const (
|
||||
DataScopeAll = "all"
|
||||
DataScopeSelf = "self"
|
||||
)
|
||||
|
||||
var dataScopeModules = []string{"session", "customer", "chat_history", "statistics"}
|
||||
|
||||
var predefinedPermissions = []Permission{
|
||||
{Code: "session.view", Name: "查看会话列表", Module: "工作台", Category: "view", SortOrder: 1},
|
||||
{Code: "session.reply", Name: "回复访客消息", Module: "工作台", Category: "operate", SortOrder: 2},
|
||||
{Code: "session.transfer", Name: "转接会话", Module: "工作台", Category: "operate", SortOrder: 3},
|
||||
{Code: "session.end", Name: "结束会话", Module: "工作台", Category: "operate", SortOrder: 4},
|
||||
{Code: "session.note", Name: "添加内部备注", Module: "工作台", Category: "operate", SortOrder: 5},
|
||||
{Code: "session.priority", Name: "标记优先级", Module: "工作台", Category: "operate", SortOrder: 6},
|
||||
{Code: "customer.view", Name: "查看客户列表", Module: "客户管理", Category: "view", SortOrder: 7},
|
||||
{Code: "customer.create", Name: "新增客户", Module: "客户管理", Category: "operate", SortOrder: 8},
|
||||
{Code: "customer.edit", Name: "编辑客户资料", Module: "客户管理", Category: "operate", SortOrder: 9},
|
||||
{Code: "customer.export", Name: "导出客户", Module: "客户管理", Category: "operate", SortOrder: 10},
|
||||
{Code: "customer.tag", Name: "管理客户标签", Module: "客户管理", Category: "operate", SortOrder: 11},
|
||||
{Code: "chat_history.view", Name: "查看对话记录", Module: "对话记录", Category: "view", SortOrder: 12},
|
||||
{Code: "chat_history.detail", Name: "查看会话详情", Module: "对话记录", Category: "view", SortOrder: 13},
|
||||
{Code: "chat_history.export", Name: "导出对话记录", Module: "对话记录", Category: "operate", SortOrder: 14},
|
||||
{Code: "chat_history.batch_archive", Name: "批量归档记录", Module: "对话记录", Category: "operate", SortOrder: 15},
|
||||
{Code: "knowledge.view", Name: "查看知识库", Module: "知识库", Category: "view", SortOrder: 16},
|
||||
{Code: "knowledge.create", Name: "新建知识条目", Module: "知识库", Category: "operate", SortOrder: 17},
|
||||
{Code: "knowledge.edit", Name: "编辑知识条目", Module: "知识库", Category: "operate", SortOrder: 18},
|
||||
{Code: "knowledge.publish", Name: "发布/下架条目", Module: "知识库", Category: "operate", SortOrder: 19},
|
||||
{Code: "knowledge.delete", Name: "删除知识条目/分类", Module: "知识库", Category: "operate", SortOrder: 20},
|
||||
{Code: "quick_reply.view", Name: "查看快捷回复", Module: "快捷回复", Category: "view", SortOrder: 21},
|
||||
{Code: "quick_reply.team_create", Name: "新建团队快捷回复", Module: "快捷回复", Category: "operate", SortOrder: 22},
|
||||
{Code: "quick_reply.team_edit", Name: "编辑/删除团队回复", Module: "快捷回复", Category: "operate", SortOrder: 23},
|
||||
{Code: "quick_reply.personal_manage", Name: "管理我的快捷回复", Module: "快捷回复", Category: "operate", SortOrder: 24},
|
||||
{Code: "blacklist.view", Name: "查看黑名单", Module: "黑名单", Category: "view", SortOrder: 25},
|
||||
{Code: "blacklist.create", Name: "拉黑访客/IP/设备", Module: "黑名单", Category: "operate", SortOrder: 26},
|
||||
{Code: "blacklist.delete", Name: "解除黑名单", Module: "黑名单", Category: "operate", SortOrder: 27},
|
||||
{Code: "statistics.view", Name: "查看数据统计", Module: "数据统计", Category: "view", SortOrder: 28},
|
||||
{Code: "statistics.export", Name: "导出报告", Module: "数据统计", Category: "operate", SortOrder: 29},
|
||||
{Code: "statistics.performance", Name: "查看客服绩效排行", Module: "数据统计", Category: "view", SortOrder: 30},
|
||||
{Code: "settings.basic", Name: "基本设置", Module: "系统设置", Category: "operate", SortOrder: 31},
|
||||
{Code: "settings.channel", Name: "渠道管理", Module: "系统设置", Category: "operate", SortOrder: 32},
|
||||
{Code: "settings.staff", Name: "坐席账号", Module: "系统设置", Category: "operate", SortOrder: 33},
|
||||
{Code: "settings.assign_rule", Name: "客服分配规则", Module: "系统设置", Category: "operate", SortOrder: 34},
|
||||
{Code: "settings.customer_tag", Name: "客户标签", Module: "系统设置", Category: "operate", SortOrder: 35},
|
||||
{Code: "settings.auto_reply", Name: "自动回复", Module: "系统设置", Category: "operate", SortOrder: 36},
|
||||
{Code: "settings.worktime", Name: "工作时间", Module: "系统设置", Category: "operate", SortOrder: 37},
|
||||
{Code: "settings.notification", Name: "通知设置", Module: "系统设置", Category: "operate", SortOrder: 38},
|
||||
{Code: "permission.view", Name: "查看角色列表", Module: "权限控制", Category: "view", SortOrder: 39},
|
||||
{Code: "permission.create_role", Name: "创建/编辑角色", Module: "权限控制", Category: "operate", SortOrder: 40},
|
||||
{Code: "permission.delete_role", Name: "删除自定义角色", Module: "权限控制", Category: "operate", SortOrder: 41},
|
||||
{Code: "permission.assign_role", Name: "给账号分配角色", Module: "权限控制", Category: "operate", SortOrder: 42},
|
||||
}
|
||||
|
||||
// PredefinedPermissions 返回系统所有权限码列表。
|
||||
func PredefinedPermissions() []Permission {
|
||||
result := make([]Permission, len(predefinedPermissions))
|
||||
copy(result, predefinedPermissions)
|
||||
return result
|
||||
}
|
||||
|
||||
// DataScopeModules 返回支持数据范围配置的业务模块。
|
||||
func DataScopeModules() []string {
|
||||
result := make([]string, len(dataScopeModules))
|
||||
copy(result, dataScopeModules)
|
||||
return result
|
||||
}
|
||||
|
||||
// DefaultRoleDataScopes 返回角色的默认数据范围。
|
||||
func DefaultRoleDataScopes(roleCode string) map[string]string {
|
||||
scope := DataScopeSelf
|
||||
if roleCode == "admin" || roleCode == "supervisor" {
|
||||
scope = DataScopeAll
|
||||
}
|
||||
result := make(map[string]string, len(dataScopeModules))
|
||||
for _, module := range dataScopeModules {
|
||||
result[module] = scope
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BuiltinRolePermissionCodes 返回内置角色对应的权限码集合。
|
||||
func BuiltinRolePermissionCodes() map[string][]string {
|
||||
return map[string][]string{
|
||||
"admin": {
|
||||
"session.view", "session.reply", "session.transfer", "session.end", "session.note", "session.priority",
|
||||
"customer.view", "customer.create", "customer.edit", "customer.export", "customer.tag",
|
||||
"chat_history.view", "chat_history.detail", "chat_history.export", "chat_history.batch_archive",
|
||||
"knowledge.view", "knowledge.create", "knowledge.edit", "knowledge.publish", "knowledge.delete",
|
||||
"quick_reply.view", "quick_reply.team_create", "quick_reply.team_edit", "quick_reply.personal_manage",
|
||||
"blacklist.view", "blacklist.create", "blacklist.delete",
|
||||
"statistics.view", "statistics.export", "statistics.performance",
|
||||
"settings.basic", "settings.channel", "settings.staff", "settings.assign_rule",
|
||||
"settings.customer_tag", "settings.auto_reply", "settings.worktime", "settings.notification",
|
||||
"permission.view", "permission.create_role", "permission.delete_role", "permission.assign_role",
|
||||
},
|
||||
"supervisor": {
|
||||
"session.view", "session.reply", "session.transfer", "session.end", "session.note", "session.priority",
|
||||
"customer.view", "customer.create", "customer.edit", "customer.export", "customer.tag",
|
||||
"chat_history.view", "chat_history.detail", "chat_history.export", "chat_history.batch_archive",
|
||||
"knowledge.view", "knowledge.create", "knowledge.edit", "knowledge.publish", "knowledge.delete",
|
||||
"quick_reply.view", "quick_reply.team_create", "quick_reply.team_edit", "quick_reply.personal_manage",
|
||||
"blacklist.view", "blacklist.create", "blacklist.delete",
|
||||
"statistics.view", "statistics.export", "statistics.performance",
|
||||
"settings.customer_tag", "settings.auto_reply",
|
||||
},
|
||||
"agent": {
|
||||
"session.view", "session.reply", "session.end", "session.note", "session.priority",
|
||||
"customer.view", "customer.create", "customer.edit", "customer.tag",
|
||||
"chat_history.view", "chat_history.detail",
|
||||
"knowledge.view",
|
||||
"quick_reply.view", "quick_reply.personal_manage",
|
||||
"statistics.view", "statistics.performance",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// EnsurePermissions 补齐并更新系统权限码,支持后续平滑新增权限项。
|
||||
func EnsurePermissions() error {
|
||||
for _, permission := range predefinedPermissions {
|
||||
if err := DB.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "code"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"name", "module", "category", "sort_order"}),
|
||||
}).Create(&permission).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureBuiltinRoles 确保指定租户拥有三个内置角色。
|
||||
func EnsureBuiltinRoles(tenantID uint) error {
|
||||
builtins := []struct{ name, code, desc string }{
|
||||
{"管理员", "admin", "租户最高权限,可管理账号、角色与全部系统设置"},
|
||||
{"客服主管", "supervisor", "管理一线团队,可查看全部数据并维护知识库、快捷回复、黑名单等"},
|
||||
{"客服", "agent", "一线接待人员,仅可查看和操作自己相关的会话、客户与个人数据"},
|
||||
}
|
||||
permMap := BuiltinRolePermissionCodes()
|
||||
|
||||
return DB.Transaction(func(tx *gorm.DB) error {
|
||||
for _, b := range builtins {
|
||||
var role Role
|
||||
created := false
|
||||
err := tx.Where("tenant_id = ? AND code = ?", tenantID, b.code).First(&role).Error
|
||||
if err != nil {
|
||||
if err != gorm.ErrRecordNotFound {
|
||||
return err
|
||||
}
|
||||
role = Role{TenantID: tenantID, Name: b.name, Code: b.code, Type: "builtin", Desc: b.desc}
|
||||
if err := tx.Create(&role).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
created = true
|
||||
}
|
||||
|
||||
var permissionCount int64
|
||||
if err := tx.Model(&RolePermission{}).Where("role_id = ?", role.ID).Count(&permissionCount).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// 新建角色或迁移期空关联才写默认权限,避免覆盖管理员的自定义配置。
|
||||
if created || permissionCount == 0 {
|
||||
var permissionIDs []uint
|
||||
if err := tx.Model(&Permission{}).Where("code IN ?", permMap[b.code]).Pluck("id", &permissionIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for _, permissionID := range permissionIDs {
|
||||
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&RolePermission{
|
||||
RoleID: role.ID, PermissionID: permissionID,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for module, scope := range DefaultRoleDataScopes(b.code) {
|
||||
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&RoleDataScope{
|
||||
RoleID: role.ID, Module: module, Scope: scope,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user