From 9171077fb9d5c9b1ebc568d1005172b52c7c30b7 Mon Sep 17 00:00:00 2001 From: yumaojun03 <719118794@qq.com> Date: Sun, 15 Jun 2025 16:35:05 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=AE=A1=E8=AE=A1=E4=B8=AD?= =?UTF-8?q?=E9=97=B4=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devcloud/audit/README.md | 19 +++++ .../audit/apps/event/consumer/consumer.go | 5 +- devcloud/audit/apps/event/consumer/impl.go | 5 ++ devcloud/audit/apps/event/impl/impl.go | 9 ++ devcloud/audit/apps/event/model.go | 2 + devcloud/audit/apps/event/priority.go | 5 ++ devcloud/audit/audit/const.go | 9 ++ devcloud/audit/audit/middleware.go | 45 ++++++++++ devcloud/audit/audit/sender.go | 82 +++++++++++++++++++ devcloud/audit/design.drawio | 59 ++++++------- devcloud/etc/application.toml | 1 + devcloud/mcenter/apps/user/api/api.go | 2 + devcloud/mcenter/permission/checker.go | 4 + 13 files changed, 210 insertions(+), 37 deletions(-) create mode 100644 devcloud/audit/apps/event/priority.go create mode 100644 devcloud/audit/audit/const.go create mode 100644 devcloud/audit/audit/sender.go diff --git a/devcloud/audit/README.md b/devcloud/audit/README.md index 3f8924d..8511a94 100644 --- a/devcloud/audit/README.md +++ b/devcloud/audit/README.md @@ -1,2 +1,21 @@ # 操作审计 +1. 路有装饰, 路有配置 +```go + // required_auth=true/false + ws.Route(ws.GET("").To(h.QueryUser). + Doc("用户列表查询"). + Metadata(restfulspec.KeyOpenAPITags, tags). + // 这个开关怎么生效 + // 中间件需求读取接口的描述信息,来决定是否需要认证 + Metadata(permission.Auth(true)). + Metadata(permission.Permission(true)). + Metadata(permission.Resource("user")). + Metadata(permission.Action("list")). + // 开启接口操作审计 + Metadata(audit.Enable(true)). + Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")). + Param(restful.QueryParameter("page_number", "页码").DataType("integer")). + Writes(Set{}). + Returns(200, "OK", Set{})) +``` \ No newline at end of file diff --git a/devcloud/audit/apps/event/consumer/consumer.go b/devcloud/audit/apps/event/consumer/consumer.go index edb9a0d..76ce030 100644 --- a/devcloud/audit/apps/event/consumer/consumer.go +++ b/devcloud/audit/apps/event/consumer/consumer.go @@ -4,7 +4,8 @@ import ( "context" "io" - "github.com/infraboard/modules/maudit/apps/event" + "122.51.31.227/go-course/go18/devcloud/audit/apps/event" + "github.com/infraboard/mcube/v2/types" ) // 读取消息,处理消息, 使用同步方法, 会阻塞 @@ -27,7 +28,7 @@ func (c *consumer) Run(ctx context.Context) error { // 发送的数据时Json格式, 接收用的JSON, 发送也需要使用JSON err = e.Load(m.Value) if err == nil { - if err := event.GetService().SaveEvent(ctx, event.NewEventSet().Add(e)); err != nil { + if err := event.GetService().SaveEvent(ctx, types.NewSet[*event.Event]().Add(e)); err != nil { c.log.Error().Msgf("save event error, %s", err) } } diff --git a/devcloud/audit/apps/event/consumer/impl.go b/devcloud/audit/apps/event/consumer/impl.go index af9892e..6100011 100644 --- a/devcloud/audit/apps/event/consumer/impl.go +++ b/devcloud/audit/apps/event/consumer/impl.go @@ -3,6 +3,7 @@ package consumer import ( "context" + "122.51.31.227/go-course/go18/devcloud/audit/apps/event" "github.com/infraboard/mcube/v2/ioc" "github.com/infraboard/mcube/v2/ioc/config/log" "github.com/rs/zerolog" @@ -53,6 +54,10 @@ func (i *consumer) Init() error { return nil } +func (i *consumer) Priority() int { + return event.PRIORITY - 1 +} + func (i *consumer) Close(ctx context.Context) error { i.ctx.Done() return nil diff --git a/devcloud/audit/apps/event/impl/impl.go b/devcloud/audit/apps/event/impl/impl.go index e237463..8f4517c 100644 --- a/devcloud/audit/apps/event/impl/impl.go +++ b/devcloud/audit/apps/event/impl/impl.go @@ -8,12 +8,17 @@ import ( ioc_mongo "github.com/infraboard/mcube/v2/ioc/config/mongo" "go.mongodb.org/mongo-driver/mongo" + + // 引入消费者 + _ "122.51.31.227/go-course/go18/devcloud/audit/apps/event/consumer" ) func init() { ioc.Controller().Registry(&EventServiceImpl{}) } +var _ event.Service = (*EventServiceImpl)(nil) + // 业务具体实现 type EventServiceImpl struct { // 继承模版 @@ -31,6 +36,10 @@ func (i *EventServiceImpl) Name() string { return event.AppName } +func (i *EventServiceImpl) Priority() int { + return event.PRIORITY +} + // 初始化 func (i *EventServiceImpl) Init() error { // 对象 diff --git a/devcloud/audit/apps/event/model.go b/devcloud/audit/apps/event/model.go index fc3efd8..3dcae5c 100644 --- a/devcloud/audit/apps/event/model.go +++ b/devcloud/audit/apps/event/model.go @@ -35,6 +35,8 @@ type Event struct { // 做了什么操作, 服务:资源:动作 // 服务 Service string `json:"service" bson:"service"` + // 哪个空间 + Namespace string `json:"namespace" bson:"namespace"` // 资源 ResourceType string `json:"resource_type" bson:"resource_type"` // 动作 diff --git a/devcloud/audit/apps/event/priority.go b/devcloud/audit/apps/event/priority.go new file mode 100644 index 0000000..1eb29e6 --- /dev/null +++ b/devcloud/audit/apps/event/priority.go @@ -0,0 +1,5 @@ +package event + +const ( + PRIORITY = 90 +) diff --git a/devcloud/audit/audit/const.go b/devcloud/audit/audit/const.go new file mode 100644 index 0000000..63dbcee --- /dev/null +++ b/devcloud/audit/audit/const.go @@ -0,0 +1,9 @@ +package audit + +const ( + META_AUDIT_KEY = "audit" +) + +func Enable(v bool) (string, bool) { + return META_AUDIT_KEY, v +} diff --git a/devcloud/audit/audit/middleware.go b/devcloud/audit/audit/middleware.go index 6fd56fb..6327791 100644 --- a/devcloud/audit/audit/middleware.go +++ b/devcloud/audit/audit/middleware.go @@ -1 +1,46 @@ package audit + +import ( + "122.51.31.227/go-course/go18/devcloud/mcenter/permission" + "github.com/infraboard/mcube/v2/ioc" + "github.com/infraboard/mcube/v2/ioc/config/gorestful" + ioc_kafka "github.com/infraboard/mcube/v2/ioc/config/kafka" + "github.com/infraboard/mcube/v2/ioc/config/log" + "github.com/rs/zerolog" + "github.com/segmentio/kafka-go" +) + +func init() { + ioc.Config().Registry(&EventSender{ + Topic: "audit_go18", + }) +} + +// 审计中间件 +type EventSender struct { + ioc.ObjectImpl + log *zerolog.Logger + + // 当前这个消费者 配置的topic + Topic string `toml:"topic" json:"topic" yaml:"topic" env:"TOPIC"` + // + wirter *kafka.Writer +} + +// 中间件对象名称 +func (c *EventSender) Name() string { + return "audit_middleware" +} + +func (c *EventSender) Priority() int { + return permission.GetCheckerPriority() - 1 +} + +func (c *EventSender) Init() error { + c.log = log.Sub(c.Name()) + c.wirter = ioc_kafka.Producer(c.Topic) + + // 注册认证中间件 + gorestful.RootRouter().Filter(c.SendEvent()) + return nil +} diff --git a/devcloud/audit/audit/sender.go b/devcloud/audit/audit/sender.go new file mode 100644 index 0000000..19eb689 --- /dev/null +++ b/devcloud/audit/audit/sender.go @@ -0,0 +1,82 @@ +package audit + +import ( + "context" + + "122.51.31.227/go-course/go18/devcloud/audit/apps/event" + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint" + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/token" + "github.com/emicklei/go-restful/v3" + "github.com/infraboard/mcube/v2/ioc/config/application" +) + +// 审计日志的发送逻辑 +func (a *EventSender) SendEvent() restful.FilterFunction { + return func(req *restful.Request, resp *restful.Response, fc *restful.FilterChain) { + sr := req.SelectedRoute() + md := NewMetaData(sr.Metadata()) + + // 开关打开,则开启审计 + if md.GetBool(META_AUDIT_KEY) { + + // 获取当前是否需要审计 + e := event.NewEvent() + + // 用户信息 + tk := token.GetTokenFromCtx(req.Request.Context()) + if tk != nil { + e.Who = tk.UserName + e.Namespace = tk.NamespaceName + } + + // ioc 里面获取当前应用的名称 + e.Service = application.Get().AppName + e.ResourceType = md.GetString(endpoint.META_RESOURCE_KEY) + e.Action = md.GetString(endpoint.META_ACTION_KEY) + + // {id} /:id + e.ResourceId = req.PathParameter("id") + e.UserAgent = req.Request.UserAgent() + e.Extras["method"] = sr.Method() + e.Extras["path"] = sr.Path() + e.Extras["operation"] = sr.Operation() + + // 补充处理后的数据 + e.StatusCode = resp.StatusCode() + // 发送给topic, 使用这个中间件的使用者,需要配置kafka + err := a.wirter.WriteMessages(context.Background(), e.ToKafkaMessage()) + if err != nil { + a.log.Error().Msgf("send message error, %s", err) + } else { + a.log.Debug().Msgf("send audit event ok, who: %s, resource: %s, action: %s", e.Who, e.ResourceType, e.Action) + } + } + + // 路有给后续逻辑 + fc.ProcessFilter(req, resp) + } +} + +func NewMetaData(data map[string]any) *MetaData { + return &MetaData{ + data: data, + } +} + +type MetaData struct { + data map[string]any +} + +func (m *MetaData) GetString(key string) string { + if v, ok := m.data[key]; ok { + return v.(string) + } + return "" +} + +func (m *MetaData) GetBool(key string) bool { + if v, ok := m.data[key]; ok { + return v.(bool) + } + return false +} diff --git a/devcloud/audit/design.drawio b/devcloud/audit/design.drawio index 0e9ac64..1799a17 100644 --- a/devcloud/audit/design.drawio +++ b/devcloud/audit/design.drawio @@ -1,91 +1,80 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - - - - - - - - - - - + - + - + - + - + - + diff --git a/devcloud/etc/application.toml b/devcloud/etc/application.toml index 964bffe..8b94ce8 100644 --- a/devcloud/etc/application.toml +++ b/devcloud/etc/application.toml @@ -18,6 +18,7 @@ endpoints = ["127.0.0.1:27017"] username = "" password = "" + database = "devcloud_go18" [kafka] brokers = ["127.0.0.1:9092"] diff --git a/devcloud/mcenter/apps/user/api/api.go b/devcloud/mcenter/apps/user/api/api.go index 7ca65d6..11479a3 100644 --- a/devcloud/mcenter/apps/user/api/api.go +++ b/devcloud/mcenter/apps/user/api/api.go @@ -1,6 +1,7 @@ package api import ( + "122.51.31.227/go-course/go18/devcloud/audit/audit" "122.51.31.227/go-course/go18/devcloud/mcenter/apps/user" "122.51.31.227/go-course/go18/devcloud/mcenter/permission" "github.com/infraboard/mcube/v2/ioc" @@ -40,6 +41,7 @@ func (h *UserRestfulApiHandler) Init() error { Metadata(permission.Permission(true)). Metadata(permission.Resource("user")). Metadata(permission.Action("list")). + Metadata(audit.Enable(true)). Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")). Param(restful.QueryParameter("page_number", "页码").DataType("integer")). Writes(Set{}). diff --git a/devcloud/mcenter/permission/checker.go b/devcloud/mcenter/permission/checker.go index 4c6a20c..847c845 100644 --- a/devcloud/mcenter/permission/checker.go +++ b/devcloud/mcenter/permission/checker.go @@ -20,6 +20,10 @@ func init() { ioc.Config().Registry(&Checker{}) } +func GetCheckerPriority() int { + return ioc.Config().Get("permission_checker").Priority() +} + func Auth(v bool) (string, bool) { return endpoint.META_REQUIRED_AUTH_KEY, v }