1
0
forked from baron/baron-sso

feat(backend): implement dynamic multi-tenancy routing and CORS

This commit is contained in:
2026-03-03 15:27:05 +09:00
parent a6e7f1253c
commit 5423f920b7
6 changed files with 277 additions and 34 deletions

View File

@@ -538,6 +538,55 @@ func (h *AuthHandler) getBearerToken(c *fiber.Ctx) string {
return parts[1]
}
func (h *AuthHandler) resolveUserfrontURL(c *fiber.Ctx) string {
// 1. Try to use the Host header from the request
host := c.Get("X-Forwarded-Host")
if host == "" {
host = c.Hostname()
}
// 2. Determine scheme
scheme := "https"
if os.Getenv("APP_ENV") == "dev" || os.Getenv("APP_ENV") == "" || c.Protocol() == "http" {
scheme = "http"
}
// 3. Fallback to env if host is not available or is localhost (and not in dev)
envURL := os.Getenv("USERFRONT_URL")
if envURL == "" {
envURL = "http://sso.hmac.kr"
}
if host == "" || (host == "localhost" && os.Getenv("APP_ENV") != "dev") {
return strings.TrimRight(envURL, "/")
}
return fmt.Sprintf("%s://%s", scheme, host)
}
func (h *AuthHandler) GetTenantInfo(c *fiber.Ctx) error {
tenantID, _ := c.Locals("tenant_id").(string)
if tenantID == "" {
return c.JSON(fiber.Map{
"isCentral": true,
})
}
tenant, err := h.TenantService.GetTenant(c.Context(), tenantID)
if err != nil {
return errorJSON(c, fiber.StatusNotFound, "Tenant not found")
}
return c.JSON(fiber.Map{
"isCentral": false,
"id": tenant.ID,
"name": tenant.Name,
"slug": tenant.Slug,
"description": tenant.Description,
"type": tenant.Type,
})
}
// normalizePhoneForLoginID는 전화번호를 IDP 조회에 적합한 형태(E.164)로 정규화합니다.
func normalizePhoneForLoginID(phone string) string {
normalized := strings.ReplaceAll(phone, "-", "")
@@ -920,10 +969,7 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error {
return errorJSON(c, fiber.StatusNotFound, "User not registered")
}
userfrontURL := os.Getenv("USERFRONT_URL")
if userfrontURL == "" {
userfrontURL = "http://sso.hmac.kr"
}
userfrontURL := h.resolveUserfrontURL(c)
if req.URI != "" {
userfrontURL = req.URI
}
@@ -1692,14 +1738,7 @@ func (h *AuthHandler) InitiatePasswordReset(c *fiber.Ctx) error {
return errorJSON(c, fiber.StatusInternalServerError, "Authentication service not configured")
}
userfrontURL := os.Getenv("USERFRONT_URL")
if userfrontURL == "" {
ale.Status = fiber.StatusInternalServerError
ale.LatencyMs = time.Since(startTime)
ale.ProviderError = "USERFRONT_URL is not set"
ale.Log(slog.LevelError, "USERFRONT_URL is not set")
return errorJSON(c, fiber.StatusInternalServerError, "USERFRONT_URL environment variable is not set")
}
userfrontURL := h.resolveUserfrontURL(c)
// [Changed] Point to Backend API for verification (which then redirects to Frontend)
redirectURL := fmt.Sprintf("%s/api/v1/auth/password/reset/verify", userfrontURL)
ale.RedirectTo = redirectURL
@@ -1863,10 +1902,7 @@ func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
ale.LoginIDs["loginId"] = loginID
ale.LoginIDs["loginId_normalized"] = loginID
userfrontURL := strings.TrimRight(os.Getenv("USERFRONT_URL"), "/")
if userfrontURL == "" {
userfrontURL = "https://sso.hmac.kr"
}
userfrontURL := h.resolveUserfrontURL(c)
redirectBase, parseErr := url.Parse(userfrontURL + "/reset-password")
if parseErr != nil {
ale.Status = fiber.StatusInternalServerError
@@ -2000,10 +2036,7 @@ func (h *AuthHandler) InitQRLogin(c *fiber.Ctx) error {
}
// QR 코드 페이로드를 실제 접속 가능한 URL로 변경합니다.
userfrontURL := os.Getenv("USERFRONT_URL")
if userfrontURL == "" {
userfrontURL = "https://sso.hmac.kr"
}
userfrontURL := h.resolveUserfrontURL(c)
qrPayload := fmt.Sprintf("%s/ql/%s", strings.TrimRight(userfrontURL, "/"), qrRef)
slog.Info("[QR] Init", "pendingRef", pendingRef, "qrRef", qrRef, "url", qrPayload)