從 edge-ai-platform POC 轉為正式產品的雲端後端,含以下整合階段:
- Phase 0:雛形骨架 — `cmd/api-server` (REST :3721) + `cmd/remote-proxy`
(tunnel :3800 / internal :3801) 雙 binary 共用 internal/,沿用 POC 的
WebSocket+yamux tunnel 協定但解耦 relay 與 API
- Phase 0.6:OIDC BFF 接 Innovedus Member Center
- internal/oidc package(coreos/go-oidc + PKCE S256 + state + nonce)
- internal/usersession package(HMAC-SHA256 cookie + RotateSessionID
防 session fixation, OWASP ASVS V3.2.1)
- 4 個 OIDC handler(/api/auth/login|callback|me|logout)+ AuthMiddleware
- 完全拔除 StaticAuthProvider,OIDC 是唯一認證路徑
- 9 個 ADR(含 ADR-010 BFF / ADR-011 取代 static auth /
ADR-012 pending session shared cookie / ADR-013 PKCE-only public client)
- Phase 0.7:A1 改造 + security audit 修復
- OIDC ClientSecret 變選填,支援 stage MC 的 public PKCE-only client
(AuthStyleInParams 強制 token endpoint 不送 client_secret)
- 預留 ServiceClient* 欄位給未來 client_credentials grant
- 移除 13+ 處 resolveUserID(uc, StaticUserID) fallback 改 strict mode
(Audit C1:multi-tenant 隔離破口)
- Pairing exchange MarkUsed 失敗 abort + revoke session token(Audit M3)
- 新增 all_endpoints_require_auth_test 整合測試(51 endpoint × 401)
驗證:go test -race -count=3 ./... 17 packages 全綠 / go vet 0 warning
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
2.2 KiB
Go
55 lines
2.2 KiB
Go
// auth.go — /api/auth/* 的 handler 註冊。
|
||
//
|
||
// OB5(2026-04-26)起,OIDC 是唯一認證路徑:
|
||
// - GET /api/auth/login → 302 to IdP(registerOIDCPublicRoutes 在 apiGroup 之外)
|
||
// - GET /api/auth/callback → token exchange + cookie session(同上)
|
||
// - POST /api/auth/login → 410 Gone(指引使用者改用 GET)
|
||
// - POST /api/auth/logout → 清 cookie session(idempotent)
|
||
// - GET /api/auth/me → 從 cookie session 拿 user info
|
||
// - POST /api/auth/register → 501(註冊去 Member Center)
|
||
//
|
||
// 對齊 api-spec.md §1(Auth)+ oidc-tdd.md §3 / §4.5。
|
||
|
||
package api
|
||
|
||
import (
|
||
"net/http"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// registerAuthRoutes 註冊 /api/auth/* 的 routes(OIDC 模式,唯一路徑)。
|
||
//
|
||
// 注意:GET /api/auth/login 與 /api/auth/callback 是「不需登入即可呼叫」的
|
||
// public endpoint,由 NewRouter 透過 registerOIDCPublicRoutes 直接註冊在 r 上
|
||
// (不在 apiGroup 中),不在這裡。
|
||
func registerAuthRoutes(g *gin.RouterGroup, deps Deps) {
|
||
g.POST("/auth/login", oidcLoginNotSupportedHandler())
|
||
g.POST("/auth/logout", oidcLogoutHandler(deps))
|
||
g.GET("/auth/me", oidcMeHandler(deps))
|
||
g.POST("/auth/register", authRegisterHandler())
|
||
}
|
||
|
||
// oidcLoginNotSupportedHandler 回 410 Gone,告訴 caller 改用 GET /api/auth/login。
|
||
//
|
||
// 為什麼選 410 而非 405:
|
||
// - 405 Method Not Allowed 暗示「同 URL 換 method 就行」 — 但語意上 OIDC login
|
||
// 是 redirect flow,不只是 method 換掉。
|
||
// - 410 Gone 明確表示「此資源已不存在於此 URL/method」,並可在訊息裡指引到正確端點。
|
||
func oidcLoginNotSupportedHandler() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
WriteError(c, http.StatusGone, ErrCodeNotImplemented,
|
||
"OIDC mode: use GET /api/auth/login to start the redirect flow", nil)
|
||
}
|
||
}
|
||
|
||
// authRegisterHandler 實作 POST /api/auth/register。
|
||
//
|
||
// OIDC 模式下 visionA 不負責註冊 — 註冊是 Member Center 的職責。
|
||
// 一律回 501,前端可顯示「請至 Member Center 註冊」。
|
||
func authRegisterHandler() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
WriteNotImplemented(c, "auth.register — registration is handled by Innovedus Member Center")
|
||
}
|
||
}
|