2025-06-22 15:14:10 +08:00

131 lines
4.6 KiB
Go

package policy
import (
"encoding/json"
"fmt"
"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/datasource"
"github.com/infraboard/mcube/v2/ioc/config/validator"
"github.com/infraboard/mcube/v2/tools/pretty"
"github.com/infraboard/modules/iam/apps"
"gorm.io/gorm"
)
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{
ResourceScope: ResourceScope{
Scope: map[string][]string{},
},
RoleId: []uint64{},
Extras: map[string]string{},
Enabled: true,
ReadOnly: false,
}
}
type CreatePolicyRequest struct {
ResourceScope
// 创建者
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
RoleId []uint64 `json:"role_id" bson:"role_id" gorm:"column:role_id;type:json;not null;serializer:json" validate:"required" description:"被关联的角色"`
// 策略过期时间
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"`
}
// 资源需要组合ResourceLabel使用
type ResourceScope struct {
// 空间
NamespaceId *uint64 `json:"namespace_id" bson:"namespace_id" gorm:"column:namespace_id;type:varchar(200);index" description:"策略生效的空间Id" optional:"true"`
// 访问范围, 需要提前定义scope, 比如环境, 后端开发小组,开发资源
Scope map[string][]string `json:"scope" bson:"scope" gorm:"column:scope;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
}
// 辅助函数:将字符串切片转换为 JSON 数组字符串
func toJsonArray(arr []string) string {
b, _ := json.Marshal(arr)
return string(b)
}
func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
if r.NamespaceId != nil {
query = query.Where("namespace = ?", r.NamespaceId)
}
switch datasource.Get().Provider {
case datasource.PROVIDER_POSTGRES:
for key, values := range r.Scope {
for k, v := range r.Scope {
// 创建一个临时 JSON 对象 {"key": ["value1", "value2"]}
jsonCondition := fmt.Sprintf(`{"%s": %s}`, k, toJsonArray(v))
query = query.Where("label @> ?", jsonCondition)
}
query = query.Where("label -->>? IN ?", key, values)
}
case datasource.PROVIDER_MYSQL:
// 过滤条件, Label
for key, values := range r.Scope {
query = query.Where("label->>? IN (?)", "$."+key, values)
}
}
return query
}
func (r *CreatePolicyRequest) Validate() error {
return validator.Validate(r)
}
func (r *CreatePolicyRequest) SetNamespaceId(namespaceId uint64) *CreatePolicyRequest {
r.NamespaceId = &namespaceId
return r
}
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"`
}