template-monorepo/internal/handler/routes.go

303 lines
8.4 KiB
Go
Raw Normal View History

2026-05-19 11:00:28 +00:00
// Code generated by goctl. DO NOT EDIT.
// goctl 1.10.1
package handler
import (
"net/http"
"time"
auth "gateway/internal/handler/auth"
2026-05-20 23:51:22 +00:00
member "gateway/internal/handler/member"
2026-05-19 11:00:28 +00:00
normal "gateway/internal/handler/normal"
permission "gateway/internal/handler/permission"
2026-05-19 11:00:28 +00:00
"gateway/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
2026-05-20 23:51:22 +00:00
server.AddRoutes(
[]rest.Route{
{
// Email + 密碼登入ZITADEL ROPG → CloudEP JWT
Method: http.MethodPost,
Path: "/login",
Handler: auth.LoginHandler(serverCtx),
},
{
// Social 登入 OAuth callback
Method: http.MethodGet,
Path: "/login/social/callback",
Handler: auth.LoginSocialCallbackHandler(serverCtx),
},
{
// Social 登入:建立 login session 並回傳 OAuth URL不含 invite
Method: http.MethodPost,
Path: "/login/social/start",
Handler: auth.LoginSocialStartHandler(serverCtx),
},
{
// Email 註冊(建立 ZITADEL + member寄 registration OTP
Method: http.MethodPost,
Path: "/register",
Handler: auth.RegisterHandler(serverCtx),
},
{
// 確認 registration OTP 並核發 JWT
Method: http.MethodPost,
Path: "/register/confirm",
Handler: auth.RegisterConfirmHandler(serverCtx),
},
{
// 重寄 registration OTP
Method: http.MethodPost,
Path: "/register/resend",
Handler: auth.RegisterResendHandler(serverCtx),
},
{
// Social 註冊 OAuth callback
Method: http.MethodGet,
Path: "/register/social/callback",
Handler: auth.RegisterSocialCallbackHandler(serverCtx),
},
{
// Social 註冊:建立 session 並回傳 OAuth URL
Method: http.MethodPost,
Path: "/register/social/start",
Handler: auth.RegisterSocialStartHandler(serverCtx),
},
{
// ZITADEL id_token 換 CloudEP JWT企業 SSO
Method: http.MethodPost,
Path: "/token/exchange",
Handler: auth.TokenExchangeHandler(serverCtx),
},
{
// 以 refresh_token 換發新的 access/refresh token
Method: http.MethodPost,
Path: "/token/refresh",
Handler: auth.TokenRefreshHandler(serverCtx),
},
},
rest.WithPrefix("/api/v1/auth"),
)
server.AddRoutes(
refactor(middleware): wire AuthJWT + CasbinRBAC via .api middleware directive Stop relying on a global server.Use(CloudEPJWT) that was invisible from the .api source. Protected routes now declare middleware explicitly in each @server block and goctl chains them into routes.go — the .api file is the single source of truth for "who needs Bearer / who needs RBAC". Concretely: - Rewrite middleware to go-zero's standard struct + Handle() pattern. AuthJWT becomes strict: missing/invalid Bearer returns 28501000 (was soft passthrough). CasbinRBAC stays nil-tolerant so dev/test boots without a policy. - Files renamed to goctl's stringx convention (authjwt_middleware.go, casbinrbac_middleware.go) so future `make gen-api` runs see them as already-generated and skip the empty stub. - Move actor context helpers (Actor, WithActor, ActorFromContext) into internal/library/actor so middleware and BOTH logic packages share one context key. Previously each logic package had its own private actorKey struct{}, so an actor injected for member was invisible to permission — the permission RBAC chain would always see "missing actor". member/permission actor.go are now thin type-alias shims. - .api files declare middleware per group: auth.api (public) → no middleware (register/login/token/...) auth.api (logout) → middleware: AuthJWT member.api → middleware: AuthJWT permission.api (catalog,me) → middleware: AuthJWT permission.api (admin ops) → middleware: AuthJWT,CasbinRBAC normal.api (/health) → no middleware - ServiceContext exposes AuthJWT / CasbinRBAC as rest.Middleware; the global server.Use(...) in gateway.go is removed. - Document the pattern in AGENTS.md (cross-agent rules) and generate/api/README.md (detailed examples + filename rules) so any future AI agent or human follows the same convention. make gen-api / gen-doc / lint / build all pass. Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 09:30:50 +00:00
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthJWT},
[]rest.Route{
{
// 登出(撤銷 access JWT 及配對 refresh JWT
Method: http.MethodPost,
Path: "/logout",
Handler: auth.LogoutHandler(serverCtx),
},
}...,
),
rest.WithPrefix("/api/v1/auth"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthJWT},
[]rest.Route{
{
// 取得當前會員 profileBearer JWT本機 dev 可 fallback X-Tenant-ID + X-UID
Method: http.MethodGet,
Path: "/me",
Handler: member.GetMemberMeHandler(serverCtx),
},
{
// 更新當前會員 profile
Method: http.MethodPatch,
Path: "/me",
Handler: member.UpdateMemberMeHandler(serverCtx),
},
{
// TOTP 狀態
Method: http.MethodGet,
Path: "/me/totp",
Handler: member.GetTOTPStatusHandler(serverCtx),
},
{
// 解除 TOTP 綁定
Method: http.MethodDelete,
Path: "/me/totp",
Handler: member.DisableTOTPHandler(serverCtx),
},
{
// 重產 TOTP 備援碼
Method: http.MethodPost,
Path: "/me/totp/backup-codes",
Handler: member.RegenerateTOTPBackupCodesHandler(serverCtx),
},
{
// 確認 TOTP 綁定
Method: http.MethodPost,
Path: "/me/totp/enroll-confirm",
Handler: member.ConfirmTOTPEnrollHandler(serverCtx),
},
{
// 開始 TOTP 綁定
Method: http.MethodPost,
Path: "/me/totp/enroll-start",
Handler: member.StartTOTPEnrollHandler(serverCtx),
},
{
// 驗證 TOTPstep-up 測試)
Method: http.MethodPost,
Path: "/me/totp/verify",
Handler: member.VerifyTOTPHandler(serverCtx),
},
{
// 確認業務 email 驗證
Method: http.MethodPost,
Path: "/me/verifications/email/confirm",
Handler: member.ConfirmEmailVerificationHandler(serverCtx),
},
{
// 開始業務 email 驗證
Method: http.MethodPost,
Path: "/me/verifications/email/start",
Handler: member.StartEmailVerificationHandler(serverCtx),
},
{
// 確認業務 phone 驗證
Method: http.MethodPost,
Path: "/me/verifications/phone/confirm",
Handler: member.ConfirmPhoneVerificationHandler(serverCtx),
},
{
// 開始業務 phone 驗證
Method: http.MethodPost,
Path: "/me/verifications/phone/start",
Handler: member.StartPhoneVerificationHandler(serverCtx),
},
}...,
),
2026-05-20 23:51:22 +00:00
rest.WithPrefix("/api/v1/members"),
)
2026-05-19 11:00:28 +00:00
server.AddRoutes(
[]rest.Route{
{
// Ping
Method: http.MethodGet,
Path: "/health",
Handler: normal.PingHandler(serverCtx),
},
},
rest.WithPrefix("/api/v1"),
rest.WithTimeout(3000*time.Millisecond),
)
server.AddRoutes(
refactor(middleware): wire AuthJWT + CasbinRBAC via .api middleware directive Stop relying on a global server.Use(CloudEPJWT) that was invisible from the .api source. Protected routes now declare middleware explicitly in each @server block and goctl chains them into routes.go — the .api file is the single source of truth for "who needs Bearer / who needs RBAC". Concretely: - Rewrite middleware to go-zero's standard struct + Handle() pattern. AuthJWT becomes strict: missing/invalid Bearer returns 28501000 (was soft passthrough). CasbinRBAC stays nil-tolerant so dev/test boots without a policy. - Files renamed to goctl's stringx convention (authjwt_middleware.go, casbinrbac_middleware.go) so future `make gen-api` runs see them as already-generated and skip the empty stub. - Move actor context helpers (Actor, WithActor, ActorFromContext) into internal/library/actor so middleware and BOTH logic packages share one context key. Previously each logic package had its own private actorKey struct{}, so an actor injected for member was invisible to permission — the permission RBAC chain would always see "missing actor". member/permission actor.go are now thin type-alias shims. - .api files declare middleware per group: auth.api (public) → no middleware (register/login/token/...) auth.api (logout) → middleware: AuthJWT member.api → middleware: AuthJWT permission.api (catalog,me) → middleware: AuthJWT permission.api (admin ops) → middleware: AuthJWT,CasbinRBAC normal.api (/health) → no middleware - ServiceContext exposes AuthJWT / CasbinRBAC as rest.Middleware; the global server.Use(...) in gateway.go is removed. - Document the pattern in AGENTS.md (cross-agent rules) and generate/api/README.md (detailed examples + filename rules) so any future AI agent or human follows the same convention. make gen-api / gen-doc / lint / build all pass. Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 09:30:50 +00:00
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthJWT},
[]rest.Route{
{
// 取得全局 Permission Catalog樹狀或扁平可篩 status/type
Method: http.MethodGet,
Path: "/catalog",
Handler: permission.GetPermissionCatalogHandler(serverCtx),
},
{
// 取得當前使用者的 role / permission map前端渲染選單
Method: http.MethodGet,
Path: "/me",
Handler: permission.GetMePermissionsHandler(serverCtx),
},
}...,
),
rest.WithPrefix("/api/v1/permissions"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthJWT, serverCtx.CasbinRBAC},
[]rest.Route{
{
// 強制重載 Casbin policy單租戶或所有租戶同步 + Pub/Sub broadcast
Method: http.MethodPost,
Path: "/policy/reload",
Handler: permission.ReloadPolicyHandler(serverCtx),
},
{
// 列出外部來源 → 內部 role 的映射zitadel / ldap / scim
Method: http.MethodGet,
Path: "/role-mappings",
Handler: permission.ListRoleMappingsHandler(serverCtx),
},
{
// Upsert 外部 IdP 群組到內部 role 的映射
Method: http.MethodPut,
Path: "/role-mappings",
Handler: permission.UpsertRoleMappingHandler(serverCtx),
},
{
// 刪除外部 → 內部 role 映射
Method: http.MethodDelete,
Path: "/role-mappings",
Handler: permission.DeleteRoleMappingHandler(serverCtx),
},
{
// 列出租戶內所有角色(含 system role
Method: http.MethodGet,
Path: "/roles",
Handler: permission.ListRolesHandler(serverCtx),
},
{
// 建立租戶自訂角色key 不可改、不可使用 system./platform_ 開頭)
Method: http.MethodPost,
Path: "/roles",
Handler: permission.CreateRoleHandler(serverCtx),
},
{
// 更新角色display_name / statusis_system 角色不可改 status
Method: http.MethodPatch,
Path: "/roles/:id",
Handler: permission.UpdateRoleHandler(serverCtx),
},
{
// 刪除角色is_system 不可刪;存在 user 指派時拒絕)
Method: http.MethodDelete,
Path: "/roles/:id",
Handler: permission.DeleteRoleHandler(serverCtx),
},
{
// 讀取角色目前勾選的 permission 集合
Method: http.MethodGet,
Path: "/roles/:id/permissions",
Handler: permission.GetRolePermissionsHandler(serverCtx),
},
{
// 全量取代角色的 permission 勾選(自動補齊父權限;觸發 LoadPolicy + Pub/Sub reload
Method: http.MethodPut,
Path: "/roles/:id/permissions",
Handler: permission.ReplaceRolePermissionsHandler(serverCtx),
},
{
// 查詢使用者目前指派的角色(含 RoleKey / DisplayName
Method: http.MethodGet,
Path: "/users/:uid/roles",
Handler: permission.ListUserRolesHandler(serverCtx),
},
{
// 指派角色給使用者(預設 source=manualsource 來源由 SyncFromX 自動標)
Method: http.MethodPost,
Path: "/users/:uid/roles",
Handler: permission.AssignUserRoleHandler(serverCtx),
},
{
// 撤銷使用者的單一角色
Method: http.MethodDelete,
Path: "/users/:uid/roles/:role_id",
Handler: permission.RevokeUserRoleHandler(serverCtx),
},
}...,
),
rest.WithPrefix("/api/v1/permissions"),
)
2026-05-19 11:00:28 +00:00
}