2025-06-08 16:14:19 +08:00
|
|
|
|
package policy
|
|
|
|
|
|
|
|
|
|
import (
|
2025-06-29 10:24:46 +08:00
|
|
|
|
"strings"
|
2025-06-08 16:14:19 +08:00
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace"
|
|
|
|
|
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/role"
|
|
|
|
|
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/user"
|
|
|
|
|
"github.com/infraboard/mcube/v2/ioc/config/validator"
|
|
|
|
|
"github.com/infraboard/mcube/v2/tools/pretty"
|
|
|
|
|
"github.com/infraboard/modules/iam/apps"
|
2025-06-22 16:29:42 +08:00
|
|
|
|
"gorm.io/datatypes"
|
2025-06-22 12:08:39 +08:00
|
|
|
|
"gorm.io/gorm"
|
2025-06-22 16:29:42 +08:00
|
|
|
|
"gorm.io/gorm/clause"
|
2025-06-08 16:14:19 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func NewPolicy() *Policy {
|
|
|
|
|
return &Policy{
|
|
|
|
|
ResourceMeta: *apps.NewResourceMeta(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Policy struct {
|
|
|
|
|
// 基础数据
|
|
|
|
|
apps.ResourceMeta
|
|
|
|
|
// 策略定义
|
|
|
|
|
CreatePolicyRequest
|
|
|
|
|
// 关联空间
|
|
|
|
|
Namespace *namespace.Namespace `json:"namespace,omitempty" gorm:"-"`
|
|
|
|
|
// 关联用户
|
|
|
|
|
User *user.User `json:"user,omitempty" gorm:"-"`
|
|
|
|
|
// 关联角色
|
|
|
|
|
Role *role.Role `json:"role,omitempty" gorm:"-"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Policy) TableName() string {
|
|
|
|
|
return "policy"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Policy) String() string {
|
|
|
|
|
return pretty.ToJSON(p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewCreatePolicyRequest() *CreatePolicyRequest {
|
|
|
|
|
return &CreatePolicyRequest{
|
2025-06-22 11:22:04 +08:00
|
|
|
|
ResourceScope: ResourceScope{
|
2025-06-22 12:08:39 +08:00
|
|
|
|
Scope: map[string][]string{},
|
2025-06-22 11:22:04 +08:00
|
|
|
|
},
|
|
|
|
|
RoleId: []uint64{},
|
2025-06-08 16:14:19 +08:00
|
|
|
|
Extras: map[string]string{},
|
|
|
|
|
Enabled: true,
|
|
|
|
|
ReadOnly: false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type CreatePolicyRequest struct {
|
2025-06-22 11:22:04 +08:00
|
|
|
|
ResourceScope
|
2025-06-08 16:14:19 +08:00
|
|
|
|
// 创建者
|
|
|
|
|
CreateBy uint64 `json:"create_by" bson:"create_by" gorm:"column:create_by;type:uint" description:"创建者" optional:"true"`
|
|
|
|
|
// 用户Id
|
|
|
|
|
UserId uint64 `json:"user_id" bson:"user_id" gorm:"column:user_id;type:uint;not null;index" validate:"required" description:"被授权的用户"`
|
|
|
|
|
// 角色Id
|
2025-06-22 11:22:04 +08:00
|
|
|
|
RoleId []uint64 `json:"role_id" bson:"role_id" gorm:"column:role_id;type:json;not null;serializer:json" validate:"required" description:"被关联的角色"`
|
2025-06-08 16:14:19 +08:00
|
|
|
|
// 策略过期时间
|
|
|
|
|
ExpiredTime *time.Time `json:"expired_time" bson:"expired_time" gorm:"column:expired_time;type:timestamp;index" description:"策略过期时间" optional:"true"`
|
|
|
|
|
// 只读策略, 不允许用户修改, 一般用于系统管理
|
|
|
|
|
ReadOnly bool `json:"read_only" bson:"read_only" gorm:"column:read_only;type:tinyint(1)" description:"只读策略, 不允许用户修改, 一般用于系统管理" optional:"true"`
|
|
|
|
|
// 该策略是否启用
|
|
|
|
|
Enabled bool `json:"enabled" bson:"enabled" gorm:"column:enabled;type:tinyint(1)" description:"该策略是否启用" optional:"true"`
|
|
|
|
|
// 策略标签
|
|
|
|
|
Label string `json:"label" gorm:"column:label;type:varchar(200);index" description:"策略标签" optional:"true"`
|
|
|
|
|
// 扩展信息
|
|
|
|
|
Extras map[string]string `json:"extras" bson:"extras" gorm:"column:extras;serializer:json;type:json" description:"扩展信息" optional:"true"`
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 12:08:39 +08:00
|
|
|
|
// 资源需要组合ResourceLabel使用
|
2025-06-22 11:22:04 +08:00
|
|
|
|
type ResourceScope struct {
|
|
|
|
|
// 空间
|
|
|
|
|
NamespaceId *uint64 `json:"namespace_id" bson:"namespace_id" gorm:"column:namespace_id;type:varchar(200);index" description:"策略生效的空间Id" optional:"true"`
|
|
|
|
|
// 访问范围, 需要提前定义scope, 比如环境, 后端开发小组,开发资源
|
2025-06-22 12:08:39 +08:00
|
|
|
|
Scope map[string][]string `json:"scope" bson:"scope" gorm:"column:scope;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-29 15:26:49 +08:00
|
|
|
|
func (r ResourceScope) String() string {
|
|
|
|
|
return pretty.ToJSON(r)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *ResourceScope) BuildMySQLPrefixBlob() {
|
|
|
|
|
for k := range r.Scope {
|
|
|
|
|
for i := range r.Scope[k] {
|
|
|
|
|
if !strings.HasSuffix(r.Scope[k][i], "%") {
|
|
|
|
|
r.Scope[k][i] += "%"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *ResourceScope) SetNamespaceId(v uint64) {
|
|
|
|
|
r.NamespaceId = &v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *ResourceScope) GetNamespaceId() uint64 {
|
|
|
|
|
if r.NamespaceId == nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
return *r.NamespaceId
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 16:29:42 +08:00
|
|
|
|
func (l *ResourceScope) SetScope(key string, value []string) {
|
|
|
|
|
if l.Scope == nil {
|
|
|
|
|
l.Scope = map[string][]string{}
|
|
|
|
|
}
|
|
|
|
|
l.Scope[key] = value
|
2025-06-22 12:08:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 15:14:10 +08:00
|
|
|
|
func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
|
2025-06-22 12:08:39 +08:00
|
|
|
|
if r.NamespaceId != nil {
|
2025-06-29 15:26:49 +08:00
|
|
|
|
query = query.Where("namespace_id = ?", r.NamespaceId)
|
2025-06-22 12:08:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 16:29:42 +08:00
|
|
|
|
for key, values := range r.Scope {
|
|
|
|
|
if len(values) == 0 {
|
|
|
|
|
continue
|
2025-06-22 12:08:39 +08:00
|
|
|
|
}
|
2025-06-22 16:29:42 +08:00
|
|
|
|
|
|
|
|
|
// 构建"标签不存在"条件
|
|
|
|
|
notHasKey := clause.Not(datatypes.JSONQuery("label").HasKey(key))
|
|
|
|
|
|
|
|
|
|
// 构建"标签值匹配"条件
|
|
|
|
|
var valueMatches []clause.Expression
|
|
|
|
|
for _, val := range values {
|
2025-06-29 10:24:46 +08:00
|
|
|
|
if strings.Contains(val, "%") {
|
|
|
|
|
// 如果值包含通配符%,使用LIKE条件
|
|
|
|
|
valueMatches = append(valueMatches,
|
|
|
|
|
clause.Expr{
|
|
|
|
|
SQL: "JSON_UNQUOTE(JSON_EXTRACT(label, ?)) LIKE ?",
|
|
|
|
|
Vars: []any{"$." + key, val},
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
// 否则使用精确匹配
|
|
|
|
|
valueMatches = append(valueMatches,
|
|
|
|
|
datatypes.JSONQuery("label").Equals(val, key))
|
|
|
|
|
}
|
2025-06-22 12:08:39 +08:00
|
|
|
|
}
|
2025-06-22 15:14:10 +08:00
|
|
|
|
|
2025-06-22 16:29:42 +08:00
|
|
|
|
// 组合条件:标签不存在 OR 标签值匹配
|
|
|
|
|
query = query.Where(clause.Or(
|
|
|
|
|
notHasKey,
|
|
|
|
|
clause.Or(valueMatches...),
|
|
|
|
|
))
|
|
|
|
|
}
|
2025-06-22 15:14:10 +08:00
|
|
|
|
return query
|
2025-06-22 11:22:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-08 16:14:19 +08:00
|
|
|
|
func (r *CreatePolicyRequest) Validate() error {
|
|
|
|
|
return validator.Validate(r)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *CreatePolicyRequest) SetNamespaceId(namespaceId uint64) *CreatePolicyRequest {
|
|
|
|
|
r.NamespaceId = &namespaceId
|
|
|
|
|
return r
|
|
|
|
|
}
|
2025-06-22 12:08:39 +08:00
|
|
|
|
|
|
|
|
|
type ResourceLabel struct {
|
|
|
|
|
// 空间
|
|
|
|
|
NamespaceId *uint64 `json:"namespace_id" bson:"namespace_id" gorm:"column:namespace_id;type:varchar(200);index" description:"策略生效的空间Id" optional:"true"`
|
|
|
|
|
// 访问范围, 需要提前定义scope, 比如环境, 后端开发小组,开发资源
|
|
|
|
|
Label map[string]string `json:"label" bson:"label" gorm:"column:label;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
|
|
|
|
|
}
|
2025-06-22 16:29:42 +08:00
|
|
|
|
|
2025-06-29 15:26:49 +08:00
|
|
|
|
func (l *ResourceLabel) SetNamespaceId(v uint64) {
|
|
|
|
|
l.NamespaceId = &v
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 16:29:42 +08:00
|
|
|
|
func (l *ResourceLabel) SetLabel(key, value string) {
|
|
|
|
|
if l.Label == nil {
|
|
|
|
|
l.Label = map[string]string{}
|
|
|
|
|
}
|
|
|
|
|
l.Label[key] = value
|
|
|
|
|
}
|