+35
-200
@@ -1,217 +1,52 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"oci-portal/internal/service"
|
||||
)
|
||||
|
||||
// NewRouter 组装全部 HTTP 路由:/auth/login 公开,业务路由要求 JWT。
|
||||
// NewRouter 组装 HTTP 路由骨架:中间件链、公开/鉴权分组与各域注册;
|
||||
// 具体路由按域拆在 routes_*.go。/auth/login 公开,业务路由要求 JWT。
|
||||
func NewRouter(auth *service.AuthService, oauth *service.OAuthService, ociConfigs *service.OciConfigService, tasks *service.TaskService, console *service.ConsoleService, settings *service.SettingService, notifier *service.Notifier, systemLogs *service.SystemLogService, logEvents *service.LogEventService, proxies *service.ProxyService, aiGateway *service.AiGatewayService) *gin.Engine {
|
||||
r := gin.New()
|
||||
// 禁用 gin 内置代理信任:真实 IP 统一由 RealIPMiddleware 按安全设置解析
|
||||
_ = r.SetTrustedProxies(nil)
|
||||
|
||||
// webhook 注册在全局 Logger 之前:访问日志不落含 secret 的路径;
|
||||
// 不挂系统日志中间件——投递高频且已在回传日志留痕,避免刷屏
|
||||
registerWebhook(r, settings, logEvents)
|
||||
|
||||
// 访问日志不落 query string:webconsole WS 的 JWT 经 query 传递,默认 Logger 会打进 stdout/journal
|
||||
accessLog := gin.LoggerWithConfig(gin.LoggerConfig{SkipQueryString: true})
|
||||
r.Use(accessLog, RealIPMiddleware(settings), IPRateMiddleware(settings), gin.Recovery())
|
||||
|
||||
v1 := r.Group("/api/v1")
|
||||
registerAuthPublic(v1, auth, oauth, systemLogs)
|
||||
// AI 网关对外端点:独立密钥鉴权,挂在全局 Use 之后,仍受 IP 限速与 Recovery 保护
|
||||
registerAiGateway(r, aiGateway)
|
||||
|
||||
// 系统日志中间件挂在鉴权之后,写请求自动留痕(webconsole ws 为 GET,天然跳过)
|
||||
secured := v1.Group("", RequireAuth(auth), systemLogMiddleware(systemLogs))
|
||||
registerAuthSecured(secured, auth, oauth, settings, systemLogs)
|
||||
registerConsole(v1, secured, console, auth)
|
||||
registerSettings(secured, settings, notifier, systemLogs, proxies)
|
||||
registerTasksAndLogs(secured, tasks, logEvents)
|
||||
registerOci(secured, ociConfigs)
|
||||
registerAiAdmin(secured, aiGateway)
|
||||
registerSwagger(r)
|
||||
|
||||
// 嵌入的前端产物兜底伺服;失败仅降级为纯 API 服务,不阻塞启动
|
||||
if err := registerWebUI(r); err != nil {
|
||||
log.Printf("[warn] webui disabled: %v", err)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// registerWebhook 挂载 ONS 回传入口。必须注册在全局 Logger 之前:
|
||||
// 访问日志不落含 secret 的路径;不挂系统日志中间件——投递高频且已在回传日志留痕。
|
||||
func registerWebhook(r *gin.Engine, settings *service.SettingService, logEvents *service.LogEventService) {
|
||||
wh := &webhookHandler{events: logEvents}
|
||||
r.POST("/api/v1/webhooks/oci-logs/:secret",
|
||||
gin.Recovery(), RealIPMiddleware(settings), wh.handle)
|
||||
|
||||
r.Use(gin.Logger(), RealIPMiddleware(settings), IPRateMiddleware(settings), gin.Recovery())
|
||||
|
||||
v1 := r.Group("/api/v1")
|
||||
ah := &authHandler{svc: auth, logs: systemLogs}
|
||||
v1.POST("/auth/login", ah.login)
|
||||
|
||||
// 外部身份登录(公开):provider 列表 / 授权跳转(bind 模式 handler 内校验 JWT)/ 回调
|
||||
ax := &authxHandler{auth: auth, oauth: oauth}
|
||||
v1.GET("/auth/oauth/providers", ax.oauthProviders)
|
||||
v1.GET("/auth/oauth/:provider/authorize", ax.oauthAuthorize)
|
||||
v1.GET("/auth/oauth/:provider/callback", ax.oauthCallback)
|
||||
|
||||
// 控制台数据面:浏览器 WebSocket 无法带自定义头,token 经 query 在 handler 内校验
|
||||
ch := &consoleHandler{svc: console, auth: auth}
|
||||
v1.GET("/console-sessions/:sessionId/ws", ch.ws)
|
||||
|
||||
// AI 网关对外端点:独立密钥鉴权(Bearer / x-api-key),不挂 JWT 与系统日志
|
||||
// (高频调用自有 AiCallLog);挂在全局 Use 之后,仍受 IP 限速与 Recovery 保护
|
||||
aih := &aiGatewayHandler{gw: aiGateway}
|
||||
ai := r.Group("/ai/v1", aih.auth)
|
||||
ai.POST("/chat/completions", aih.chatCompletions)
|
||||
ai.POST("/responses", aih.responses)
|
||||
ai.POST("/messages", aih.messages)
|
||||
ai.POST("/embeddings", aih.embeddings)
|
||||
ai.GET("/models", aih.listModels)
|
||||
|
||||
// 系统日志中间件挂在鉴权之后,写请求自动留痕(webconsole ws 为 GET,天然跳过)
|
||||
secured := v1.Group("", RequireAuth(auth), systemLogMiddleware(systemLogs))
|
||||
secured.POST("/auth/logout", ah.logout)
|
||||
secured.GET("/regions", listRegions)
|
||||
secured.GET("/system-logs", (&systemLogHandler{svc: systemLogs}).list)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/console-sessions", ch.create)
|
||||
secured.DELETE("/console-sessions/:sessionId", ch.remove)
|
||||
|
||||
st := &settingsHandler{svc: settings, notifier: notifier}
|
||||
secured.GET("/about", about)
|
||||
secured.GET("/settings/telegram", st.getTelegram)
|
||||
secured.PUT("/settings/telegram", st.updateTelegram)
|
||||
secured.POST("/settings/telegram/test", st.testTelegram)
|
||||
secured.GET("/settings/notify-events", st.getNotifyEvents)
|
||||
secured.PUT("/settings/notify-events", st.updateNotifyEvents)
|
||||
secured.GET("/settings/notify-templates", st.listNotifyTemplates)
|
||||
secured.PUT("/settings/notify-templates/:kind", st.updateNotifyTemplate)
|
||||
secured.POST("/settings/notify-templates/:kind/test", st.testNotifyTemplate)
|
||||
secured.GET("/settings/task", st.getTaskSettings)
|
||||
secured.PUT("/settings/task", st.updateTaskSettings)
|
||||
secured.GET("/settings/security", st.getSecurity)
|
||||
secured.PUT("/settings/security", st.updateSecurity)
|
||||
|
||||
// 两步验证与外部身份管理(JWT 组内)
|
||||
secured.GET("/auth/totp", ax.totpStatus)
|
||||
secured.POST("/auth/totp/setup", ax.totpSetup)
|
||||
secured.POST("/auth/totp/activate", ax.totpActivate)
|
||||
secured.POST("/auth/totp/disable", ax.totpDisable)
|
||||
secured.GET("/auth/credentials", ax.getCredentials)
|
||||
secured.PUT("/auth/credentials", ax.updateCredentials)
|
||||
secured.PUT("/auth/password-login", ax.updatePasswordLogin)
|
||||
secured.GET("/auth/identities", ax.identities)
|
||||
secured.DELETE("/auth/identities/:id", ax.unbindIdentity)
|
||||
secured.GET("/settings/oauth", func(c *gin.Context) { ax.getOAuthSettings(c, settings) })
|
||||
secured.PUT("/settings/oauth", func(c *gin.Context) { ax.updateOAuthSettings(c, settings) })
|
||||
|
||||
px := &proxyHandler{svc: proxies}
|
||||
secured.GET("/proxies", px.list)
|
||||
secured.POST("/proxies", px.create)
|
||||
secured.POST("/proxies/import", px.importBatch)
|
||||
secured.PUT("/proxies/:id", px.update)
|
||||
secured.DELETE("/proxies/:id", px.remove)
|
||||
secured.POST("/proxies/:id/probe", px.probe)
|
||||
|
||||
le := &logEventHandler{svc: logEvents}
|
||||
secured.GET("/log-events", le.list)
|
||||
secured.GET("/oci-configs/:id/log-webhook", le.getWebhook)
|
||||
secured.POST("/oci-configs/:id/log-webhook", le.ensureWebhook)
|
||||
secured.DELETE("/oci-configs/:id/log-webhook", le.revokeWebhook)
|
||||
secured.GET("/oci-configs/:id/log-relay", le.getRelay)
|
||||
secured.POST("/oci-configs/:id/log-relay", le.setupRelay)
|
||||
secured.DELETE("/oci-configs/:id/log-relay", le.teardownRelay)
|
||||
|
||||
t := &taskHandler{svc: tasks}
|
||||
secured.POST("/tasks", t.create)
|
||||
secured.GET("/tasks", t.list)
|
||||
secured.GET("/tasks/:id", t.get)
|
||||
secured.PUT("/tasks/:id", t.update)
|
||||
secured.DELETE("/tasks/:id", t.remove)
|
||||
secured.GET("/tasks/:id/logs", t.logs)
|
||||
secured.POST("/tasks/:id/run", t.run)
|
||||
|
||||
h := &ociConfigHandler{svc: ociConfigs}
|
||||
secured.GET("/overview", h.overview)
|
||||
secured.POST("/oci-configs", h.create)
|
||||
secured.GET("/oci-configs", h.list)
|
||||
secured.GET("/oci-configs/:id", h.get)
|
||||
secured.PUT("/oci-configs/:id", h.update)
|
||||
secured.POST("/oci-configs/:id/verify", h.verify)
|
||||
secured.DELETE("/oci-configs/:id", h.remove)
|
||||
secured.GET("/oci-configs/:id/compartments", h.compartments)
|
||||
secured.GET("/oci-configs/:id/cached-regions", h.cachedRegions)
|
||||
secured.GET("/oci-configs/:id/cached-compartments", h.cachedCompartments)
|
||||
secured.GET("/oci-configs/:id/region-subscriptions", h.regionSubscriptions)
|
||||
secured.POST("/oci-configs/:id/region-subscriptions", h.subscribeRegion)
|
||||
secured.GET("/oci-configs/:id/limits", h.limits)
|
||||
secured.GET("/oci-configs/:id/limits/services", h.limitServices)
|
||||
secured.GET("/oci-configs/:id/subscriptions", h.subscriptions)
|
||||
secured.GET("/oci-configs/:id/subscriptions/:subscriptionId", h.subscriptionDetail)
|
||||
secured.GET("/oci-configs/:id/shapes", h.shapes)
|
||||
secured.GET("/oci-configs/:id/images", h.images)
|
||||
secured.GET("/oci-configs/:id/images/:imageId", h.getImage)
|
||||
secured.GET("/oci-configs/:id/vcns", h.listVCNs)
|
||||
secured.POST("/oci-configs/:id/vcns", h.createVCN)
|
||||
secured.GET("/oci-configs/:id/vcns/:vcnId", h.getVCN)
|
||||
secured.PUT("/oci-configs/:id/vcns/:vcnId", h.updateVCN)
|
||||
secured.DELETE("/oci-configs/:id/vcns/:vcnId", h.deleteVCN)
|
||||
secured.POST("/oci-configs/:id/vcns/:vcnId/enable-ipv6", h.enableVCNIPv6)
|
||||
secured.GET("/oci-configs/:id/subnets", h.listSubnets)
|
||||
secured.POST("/oci-configs/:id/subnets", h.createSubnet)
|
||||
secured.GET("/oci-configs/:id/subnets/:subnetId", h.getSubnet)
|
||||
secured.PUT("/oci-configs/:id/subnets/:subnetId", h.updateSubnet)
|
||||
secured.DELETE("/oci-configs/:id/subnets/:subnetId", h.deleteSubnet)
|
||||
secured.GET("/oci-configs/:id/security-lists", h.listSecurityLists)
|
||||
secured.POST("/oci-configs/:id/security-lists", h.createSecurityList)
|
||||
secured.GET("/oci-configs/:id/security-lists/:securityListId", h.getSecurityList)
|
||||
secured.PUT("/oci-configs/:id/security-lists/:securityListId", h.updateSecurityList)
|
||||
secured.DELETE("/oci-configs/:id/security-lists/:securityListId", h.deleteSecurityList)
|
||||
secured.GET("/oci-configs/:id/availability-domains", h.availabilityDomains)
|
||||
secured.GET("/oci-configs/:id/instances", h.listInstances)
|
||||
secured.POST("/oci-configs/:id/instances", h.createInstance)
|
||||
secured.GET("/oci-configs/:id/instances/:instanceId", h.getInstance)
|
||||
secured.PUT("/oci-configs/:id/instances/:instanceId", h.updateInstance)
|
||||
secured.DELETE("/oci-configs/:id/instances/:instanceId", h.terminateInstance)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/action", h.instanceAction)
|
||||
secured.GET("/oci-configs/:id/boot-volumes", h.listBootVolumes)
|
||||
secured.GET("/oci-configs/:id/boot-volumes/:bootVolumeId", h.getBootVolume)
|
||||
secured.PUT("/oci-configs/:id/boot-volumes/:bootVolumeId", h.updateBootVolume)
|
||||
secured.DELETE("/oci-configs/:id/boot-volumes/:bootVolumeId", h.deleteBootVolume)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/change-public-ip", h.changePublicIP)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/ipv6-addresses", h.addInstanceIpv6)
|
||||
secured.DELETE("/oci-configs/:id/instances/:instanceId/ipv6-addresses", h.deleteInstanceIpv6)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/console-connections", h.createConsoleConnection)
|
||||
secured.GET("/oci-configs/:id/instances/:instanceId/console-connections", h.listConsoleConnections)
|
||||
secured.DELETE("/oci-configs/:id/console-connections/:connectionId", h.deleteConsoleConnection)
|
||||
secured.GET("/oci-configs/:id/instances/:instanceId/vnics", h.listInstanceVnics)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/vnics", h.attachVnic)
|
||||
secured.DELETE("/oci-configs/:id/vnic-attachments/:attachmentId", h.detachVnic)
|
||||
secured.POST("/oci-configs/:id/vnics/:vnicId/ipv6-addresses", h.addVnicIpv6)
|
||||
secured.GET("/oci-configs/:id/instances/:instanceId/boot-volume-attachments", h.listBootVolumeAttachments)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/boot-volume-attachments", h.attachBootVolume)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/replace-boot-volume", h.replaceBootVolume)
|
||||
secured.DELETE("/oci-configs/:id/boot-volume-attachments/:attachmentId", h.detachBootVolume)
|
||||
secured.GET("/oci-configs/:id/volumes", h.listBlockVolumes)
|
||||
secured.GET("/oci-configs/:id/instances/:instanceId/volume-attachments", h.listVolumeAttachments)
|
||||
secured.POST("/oci-configs/:id/instances/:instanceId/volume-attachments", h.attachVolume)
|
||||
secured.DELETE("/oci-configs/:id/volume-attachments/:attachmentId", h.detachVolume)
|
||||
secured.GET("/oci-configs/:id/instances/:instanceId/traffic", h.instanceTraffic)
|
||||
secured.GET("/oci-configs/:id/costs", h.costs)
|
||||
// AI 网关面板管理:密钥 / 渠道(号池)/ 聚合模型 / 调用日志
|
||||
aiadmin := &aiAdminHandler{gw: aiGateway}
|
||||
secured.GET("/ai-keys", aiadmin.listKeys)
|
||||
secured.POST("/ai-keys", aiadmin.createKey)
|
||||
secured.PUT("/ai-keys/:id", aiadmin.updateKey)
|
||||
secured.PUT("/ai-keys/:id/content-log", aiadmin.updateKeyContentLog)
|
||||
secured.DELETE("/ai-keys/:id", aiadmin.deleteKey)
|
||||
secured.GET("/ai-channels", aiadmin.listChannels)
|
||||
secured.POST("/ai-channels", aiadmin.createChannel)
|
||||
secured.PUT("/ai-channels/:id", aiadmin.updateChannel)
|
||||
secured.DELETE("/ai-channels/:id", aiadmin.deleteChannel)
|
||||
secured.POST("/ai-channels/:id/probe", aiadmin.probeChannel)
|
||||
secured.POST("/ai-channels/:id/sync-models", aiadmin.syncChannelModels)
|
||||
secured.GET("/ai-models", aiadmin.gatewayModels)
|
||||
secured.GET("/ai-logs", aiadmin.listLogs)
|
||||
secured.GET("/ai-content-logs", aiadmin.listContentLogs)
|
||||
secured.GET("/oci-configs/:id/audit-events", h.getAuditEvents)
|
||||
secured.GET("/oci-configs/:id/audit-events/detail", h.getAuditEventDetail)
|
||||
secured.GET("/oci-configs/:id/users", h.listTenantUsers)
|
||||
secured.POST("/oci-configs/:id/users", h.createTenantUser)
|
||||
secured.GET("/oci-configs/:id/users/:userId", h.getTenantUserDetail)
|
||||
secured.PUT("/oci-configs/:id/users/:userId", h.updateTenantUser)
|
||||
secured.DELETE("/oci-configs/:id/users/:userId", h.deleteTenantUser)
|
||||
secured.POST("/oci-configs/:id/users/:userId/reset-password", h.resetTenantUserPassword)
|
||||
secured.DELETE("/oci-configs/:id/users/:userId/mfa-devices", h.deleteTenantUserMfa)
|
||||
secured.DELETE("/oci-configs/:id/users/:userId/api-keys", h.deleteTenantUserApiKeys)
|
||||
secured.GET("/oci-configs/:id/notification-recipients", h.getNotificationRecipients)
|
||||
secured.PUT("/oci-configs/:id/notification-recipients", h.updateNotificationRecipients)
|
||||
secured.GET("/oci-configs/:id/password-policies", h.listPasswordPolicies)
|
||||
secured.PUT("/oci-configs/:id/password-policies/:policyId", h.updatePasswordPolicy)
|
||||
secured.GET("/oci-configs/:id/identity-settings", h.getIdentitySetting)
|
||||
secured.PUT("/oci-configs/:id/identity-settings", h.updateIdentitySetting)
|
||||
secured.GET("/oci-configs/:id/identity-providers", h.listIdentityProviders)
|
||||
secured.POST("/oci-configs/:id/identity-providers", h.createIdentityProvider)
|
||||
secured.POST("/oci-configs/:id/identity-providers/:idpId/activate", h.activateIdentityProvider)
|
||||
secured.DELETE("/oci-configs/:id/identity-providers/:idpId", h.deleteIdentityProvider)
|
||||
secured.GET("/oci-configs/:id/saml-metadata", h.downloadSamlMetadata)
|
||||
secured.GET("/oci-configs/:id/sign-on-rules", h.listSignOnRules)
|
||||
secured.POST("/oci-configs/:id/sign-on-exemptions", h.createMfaExemption)
|
||||
secured.DELETE("/oci-configs/:id/sign-on-exemptions/:ruleId", h.deleteMfaExemption)
|
||||
return r
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user