2025-06-29 15:26:49 +08:00

182 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package policy
import (
"strings"
"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"
"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
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"`
}
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
}
func (l *ResourceScope) SetScope(key string, value []string) {
if l.Scope == nil {
l.Scope = map[string][]string{}
}
l.Scope[key] = value
}
func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
if r.NamespaceId != nil {
query = query.Where("namespace_id = ?", r.NamespaceId)
}
for key, values := range r.Scope {
if len(values) == 0 {
continue
}
// 构建"标签不存在"条件
notHasKey := clause.Not(datatypes.JSONQuery("label").HasKey(key))
// 构建"标签值匹配"条件
var valueMatches []clause.Expression
for _, val := range values {
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))
}
}
// 组合条件:标签不存在 OR 标签值匹配
query = query.Where(clause.Or(
notHasKey,
clause.Or(valueMatches...),
))
}
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"`
}
func (l *ResourceLabel) SetNamespaceId(v uint64) {
l.NamespaceId = &v
}
func (l *ResourceLabel) SetLabel(key, value string) {
if l.Label == nil {
l.Label = map[string]string{}
}
l.Label[key] = value
}