From 0d40c5aa09c8fb72a98e18fcff2928f4c3872c43 Mon Sep 17 00:00:00 2001 From: luorijun Date: Tue, 13 May 2025 15:26:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=A3=E7=90=86=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=9A=84=E7=A6=BB=E7=BA=BF=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=A4=E8=AF=81=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E4=BB=A3=E7=90=86=E6=9C=8D=E5=8A=A1=E8=A1=A8=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/fill/main.go | 16 ++++++++++++++ scripts/sql/init.sql | 10 ++++++--- web/auth/authenticate.go | 21 +++++++++--------- web/auth/context.go | 4 ++++ web/handlers/proxy.go | 46 ++++++++++++++++++++++++++++++++++++++-- web/models/proxy.gen.go | 1 + web/queries/proxy.gen.go | 6 +++++- web/router.go | 1 + 8 files changed, 88 insertions(+), 17 deletions(-) diff --git a/cmd/fill/main.go b/cmd/fill/main.go index c292539..26cf268 100644 --- a/cmd/fill/main.go +++ b/cmd/fill/main.go @@ -71,6 +71,11 @@ func main() { return err } + proxySecret, err := bcrypt.GenerateFromPassword([]byte("proxy"), bcrypt.DefaultCost) + if err != nil { + return err + } + err = q.Client. Select( q.Client.ClientID, @@ -96,6 +101,17 @@ func main() { GrantClient: true, Spec: int32(client2.SpecTrusted), Name: "异步任务处理服务", + }, &m.Client{ + ClientID: "proxy", + ClientSecret: string(proxySecret), + GrantClient: true, + Spec: int32(client2.SpecTrusted), + Name: "代理转发服务", + }, &m.Client{ + ClientID: "edge", + GrantClient: true, + Spec: int32(client2.SpecWeb), + Name: "代理边缘节点", }) if err != nil { return err diff --git a/scripts/sql/init.sql b/scripts/sql/init.sql index b2f1e1a..ba3f515 100644 --- a/scripts/sql/init.sql +++ b/scripts/sql/init.sql @@ -516,14 +516,17 @@ create table proxy ( version int not null, name varchar(255) not null unique, host varchar(255) not null, - type int not null default 0, secret varchar(255), - created_at timestamp default current_timestamp, - updated_at timestamp default current_timestamp, + type int not null, + status int not null, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, deleted_at timestamp ); create index proxy_name_index on proxy (name); create index proxy_host_index on proxy (host); +create index proxy_type_index on proxy (type); +create index proxy_status_index on proxy (status); create index proxy_deleted_at_index on proxy (deleted_at); -- proxy表字段注释 @@ -534,6 +537,7 @@ comment on column proxy.name is '代理服务名称'; comment on column proxy.host is '代理服务地址'; comment on column proxy.type is '代理服务类型:1-三方,2-自有'; comment on column proxy.secret is '代理服务密钥'; +comment on column proxy.status is '代理服务状态:0-离线,1-在线'; comment on column proxy.created_at is '创建时间'; comment on column proxy.updated_at is '更新时间'; comment on column proxy.deleted_at is '删除时间'; diff --git a/web/auth/authenticate.go b/web/auth/authenticate.go index 1a9613f..9aa736b 100644 --- a/web/auth/authenticate.go +++ b/web/auth/authenticate.go @@ -43,11 +43,13 @@ func Protect(c *fiber.Ctx, types []PayloadType, permissions []string) (*Context, var header = c.Get("Authorization") var split = strings.Split(header, " ") if len(split) != 2 { + slog.Debug("Authorization 头格式不正确") return nil, fiber.NewError(fiber.StatusUnauthorized, "无效的令牌") } - var token = split[1] + var token = strings.TrimSpace(split[1]) if token == "" { + slog.Debug("提供的令牌为空") return nil, fiber.NewError(fiber.StatusUnauthorized, "无效的令牌") } @@ -63,7 +65,7 @@ func Protect(c *fiber.Ctx, types []PayloadType, permissions []string) (*Context, } case "Basic": - if !slices.Contains(types, PayloadSecuredServer) { + if !slices.Contains(types, PayloadInternalServer) { slog.Debug("禁止使用 Basic 认证方式") return nil, fiber.NewError(fiber.StatusUnauthorized, "无效的令牌") } @@ -74,18 +76,18 @@ func Protect(c *fiber.Ctx, types []PayloadType, permissions []string) (*Context, } default: - slog.Debug("无效的认证方式") + slog.Debug("无效的认证方式", "method", split[0]) return nil, fiber.NewError(fiber.StatusUnauthorized, "无效的令牌") } // 检查权限 if !slices.Contains(types, auth.Payload.Type) { - slog.Debug("无效的认证主体") + slog.Debug("无效的负载类型", "except", types, "actual", auth.Payload.Type) return nil, fiber.NewError(fiber.StatusForbidden, "没有权限") } if len(permissions) > 0 && !auth.AnyPermission(permissions...) { - slog.Debug("无效的认证权限") + slog.Debug("无效的认证权限", "except", permissions, "actual", auth.Permissions) return nil, fiber.NewError(fiber.StatusForbidden, "没有权限") } @@ -114,15 +116,12 @@ func authBasic(_ context.Context, token string) (*Context, error) { // 解析 Basic 认证信息 var base, err = base64.RawURLEncoding.DecodeString(token) if err != nil { - slog.Debug(err.Error()) - return nil, err + return nil, errors.New("令牌格式错误,无法解析令牌") } var split = strings.Split(string(base), ":") if len(split) != 2 { - msg := "无法解析 Basic 认证信息" - slog.Debug(msg) - return nil, errors.New(msg) + return nil, errors.New("令牌格式错误,必须是 : 格式") } var clientID = split[0] @@ -151,7 +150,7 @@ func authBasic(_ context.Context, token string) (*Context, error) { return &Context{ Payload: Payload{ Id: client.ID, - Type: PayloadSecuredServer, + Type: PayloadTypeFromClientSpec(client2.Spec(client.Spec)), Name: client.Name, Avatar: client.Icon, }, diff --git a/web/auth/context.go b/web/auth/context.go index 7bb2067..7907ac4 100644 --- a/web/auth/context.go +++ b/web/auth/context.go @@ -65,6 +65,8 @@ func (t PayloadType) ToStr() string { return "cpub" case PayloadSecuredServer: return "ccnf" + case PayloadInternalServer: + return "inte" default: return "none" } @@ -80,6 +82,8 @@ func PayloadTypeFromStr(name string) PayloadType { return PayloadPublicServer case "ccnf": return PayloadSecuredServer + case "inte": + return PayloadInternalServer default: return PayloadNone } diff --git a/web/handlers/proxy.go b/web/handlers/proxy.go index 1edfeeb..122b55a 100644 --- a/web/handlers/proxy.go +++ b/web/handlers/proxy.go @@ -3,6 +3,7 @@ package handlers import ( "github.com/gofiber/fiber/v2" "gorm.io/gorm/clause" + "log/slog" auth2 "platform/web/auth" proxy2 "platform/web/domains/proxy" g "platform/web/globals" @@ -10,7 +11,9 @@ import ( q "platform/web/queries" ) -type RegisterProxyReq struct { +// region OnlineProxy + +type OnlineProxyReq struct { Name string `json:"name" validate:"required"` Version int `json:"version" validate:"required"` } @@ -26,13 +29,14 @@ func OnlineProxy(c *fiber.Ctx) (err error) { } // 验证请求参数 - var req = new(RegisterProxyReq) + var req = new(OnlineProxyReq) err = g.Validator.Validate(c, req) if err != nil { return err } // 创建代理 + slog.Debug("注册转发服务", "ip", c.IP()) err = q.Proxy. Clauses(clause.OnConflict{ UpdateAll: true, @@ -45,6 +49,7 @@ func OnlineProxy(c *fiber.Ctx) (err error) { Version: int32(req.Version), Host: c.IP(), Type: int32(proxy2.TypeSelfHosted), + Status: 1, }) if err != nil { return err @@ -52,3 +57,40 @@ func OnlineProxy(c *fiber.Ctx) (err error) { return nil } + +// endregion + +// region OfflineProxy + +type OfflineProxyReq struct { + Name string `json:"name" validate:"required"` +} + +func OfflineProxy(c *fiber.Ctx) (err error) { + // 检查接口权限 + _, err = auth2.NewProtect(c).Payload( + auth2.PayloadInternalServer, + ).Do() + if err != nil { + return err + } + + // 验证请求参数 + var req = new(OfflineProxyReq) + err = g.Validator.Validate(c, req) + if err != nil { + return err + } + + // 下线转发服务 + _, err = q.Proxy. + Where(q.Proxy.Name.Eq(req.Name)). + UpdateSimple(q.Proxy.Status.Value(0)) + if err != nil { + return err + } + + return nil +} + +// endregion diff --git a/web/models/proxy.gen.go b/web/models/proxy.gen.go index b57aaa8..22aa039 100644 --- a/web/models/proxy.gen.go +++ b/web/models/proxy.gen.go @@ -23,6 +23,7 @@ type Proxy struct { CreatedAt orm.LocalDateTime `gorm:"column:created_at;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 UpdatedAt orm.LocalDateTime `gorm:"column:updated_at;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:删除时间" json:"deleted_at"` // 删除时间 + Status int32 `gorm:"column:status;not null;comment:代理服务状态:0-离线,1-在线" json:"status"` // 代理服务状态:0-离线,1-在线 Edges []Edge `gorm:"foreignKey:ProxyID;references:ID" json:"edges"` } diff --git a/web/queries/proxy.gen.go b/web/queries/proxy.gen.go index 65c154d..f86413f 100644 --- a/web/queries/proxy.gen.go +++ b/web/queries/proxy.gen.go @@ -36,6 +36,7 @@ func newProxy(db *gorm.DB, opts ...gen.DOOption) proxy { _proxy.CreatedAt = field.NewField(tableName, "created_at") _proxy.UpdatedAt = field.NewField(tableName, "updated_at") _proxy.DeletedAt = field.NewField(tableName, "deleted_at") + _proxy.Status = field.NewInt32(tableName, "status") _proxy.Edges = proxyHasManyEdges{ db: db.Session(&gorm.Session{}), @@ -60,6 +61,7 @@ type proxy struct { CreatedAt field.Field // 创建时间 UpdatedAt field.Field // 更新时间 DeletedAt field.Field // 删除时间 + Status field.Int32 // 代理服务状态:0-离线,1-在线 Edges proxyHasManyEdges fieldMap map[string]field.Expr @@ -86,6 +88,7 @@ func (p *proxy) updateTableName(table string) *proxy { p.CreatedAt = field.NewField(table, "created_at") p.UpdatedAt = field.NewField(table, "updated_at") p.DeletedAt = field.NewField(table, "deleted_at") + p.Status = field.NewInt32(table, "status") p.fillFieldMap() @@ -102,7 +105,7 @@ func (p *proxy) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } func (p *proxy) fillFieldMap() { - p.fieldMap = make(map[string]field.Expr, 10) + p.fieldMap = make(map[string]field.Expr, 11) p.fieldMap["id"] = p.ID p.fieldMap["version"] = p.Version p.fieldMap["name"] = p.Name @@ -112,6 +115,7 @@ func (p *proxy) fillFieldMap() { p.fieldMap["created_at"] = p.CreatedAt p.fieldMap["updated_at"] = p.UpdatedAt p.fieldMap["deleted_at"] = p.DeletedAt + p.fieldMap["status"] = p.Status } diff --git a/web/router.go b/web/router.go index 2779944..6709d4a 100644 --- a/web/router.go +++ b/web/router.go @@ -66,6 +66,7 @@ func ApplyRouters(app *fiber.App) { // 网关 proxy := api.Group("/proxy") proxy.Post("/online", handlers.OnlineProxy) + proxy.Post("/offline", handlers.OfflineProxy) // 节点 edge := api.Group("/edge")