forked from baron/baron-sso
테넌트 등록 방식을 결정
This commit is contained in:
@@ -3,6 +3,7 @@ package handler
|
||||
import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"baron-sso-backend/internal/logger"
|
||||
"baron-sso-backend/internal/repository"
|
||||
"baron-sso-backend/internal/service"
|
||||
"baron-sso-backend/internal/utils"
|
||||
"bytes"
|
||||
@@ -78,6 +79,8 @@ type AuthHandler struct {
|
||||
IdpProvider domain.IdentityProvider
|
||||
AuditRepo domain.AuditRepository
|
||||
Hydra *service.HydraAdminService
|
||||
TenantService service.TenantService
|
||||
UserRepo repository.UserRepository
|
||||
}
|
||||
|
||||
type signupState struct {
|
||||
@@ -135,7 +138,7 @@ func checkPollInterval(redis *service.RedisService, key string, interval time.Du
|
||||
return false, int(interval.Seconds())
|
||||
}
|
||||
|
||||
func NewAuthHandler(redisService *service.RedisService, idpProvider domain.IdentityProvider, auditRepo domain.AuditRepository) *AuthHandler {
|
||||
func NewAuthHandler(redisService *service.RedisService, idpProvider domain.IdentityProvider, auditRepo domain.AuditRepository, tenantService service.TenantService, userRepo repository.UserRepository) *AuthHandler {
|
||||
projectID := os.Getenv("DESCOPE_PROJECT_ID")
|
||||
managementKey := os.Getenv("DESCOPE_MANAGEMENT_KEY")
|
||||
|
||||
@@ -161,6 +164,8 @@ func NewAuthHandler(redisService *service.RedisService, idpProvider domain.Ident
|
||||
IdpProvider: idpProvider,
|
||||
AuditRepo: auditRepo,
|
||||
Hydra: service.NewHydraAdminService(),
|
||||
TenantService: tenantService,
|
||||
UserRepo: userRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,6 +362,9 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
if req.Email == "" || req.Password == "" || req.Name == "" || req.Phone == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Missing required fields"})
|
||||
}
|
||||
if !strings.Contains(req.Email, "@") || !strings.Contains(req.Email, ".") {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid email format"})
|
||||
}
|
||||
if !req.TermsAccepted {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Terms must be accepted"})
|
||||
}
|
||||
@@ -385,6 +393,20 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Identity provider unavailable"})
|
||||
}
|
||||
|
||||
// [New] Auto-Assign Tenant by Domain
|
||||
companyCode := req.CompanyCode
|
||||
if companyCode == "" {
|
||||
parts := strings.Split(req.Email, "@")
|
||||
if len(parts) == 2 {
|
||||
domainName := parts[1]
|
||||
tenant, err := h.TenantService.GetTenantByDomain(c.Context(), domainName)
|
||||
if err == nil && tenant != nil {
|
||||
slog.Info("[Signup] Auto-assigning tenant", "email", req.Email, "tenant", tenant.Slug)
|
||||
companyCode = tenant.Slug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize Phone (E.164 형태로 보관)
|
||||
normalizedPhone := strings.ReplaceAll(req.Phone, "-", "")
|
||||
normalizedPhone = strings.ReplaceAll(normalizedPhone, " ", "")
|
||||
@@ -398,7 +420,7 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
attributes := map[string]interface{}{
|
||||
"department": req.Department,
|
||||
"affiliationType": req.AffiliationType,
|
||||
"companyCode": req.CompanyCode,
|
||||
"companyCode": companyCode,
|
||||
// grade는 기존 스키마 필수 키이므로 기본값을 설정
|
||||
"grade": "member",
|
||||
}
|
||||
@@ -427,6 +449,31 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
|
||||
slog.Info("[Signup] New user registered", "email", req.Email, "type", req.AffiliationType, "provider", h.IdpProvider.Name(), "subject", providerID)
|
||||
|
||||
// [New] Local DB Sync
|
||||
localUser := &domain.User{
|
||||
ID: providerID, // Match IDP Subject
|
||||
Email: req.Email,
|
||||
Name: req.Name,
|
||||
Phone: normalizedPhone,
|
||||
AffiliationType: req.AffiliationType,
|
||||
CompanyCode: companyCode,
|
||||
Department: req.Department,
|
||||
Role: "user",
|
||||
Status: "active",
|
||||
}
|
||||
|
||||
// Link TenantID if possible
|
||||
if companyCode != "" {
|
||||
if tenant, err := h.TenantService.GetTenantBySlug(c.Context(), companyCode); err == nil && tenant != nil {
|
||||
localUser.TenantID = &tenant.ID
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.UserRepo.Create(c.Context(), localUser); err != nil {
|
||||
slog.Error("[Signup] Failed to sync user to local DB", "email", req.Email, "error", err)
|
||||
// We don't fail the whole signup if local sync fails
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "User registered successfully",
|
||||
@@ -2057,6 +2104,13 @@ func (h *AuthHandler) GetMe(c *fiber.Ctx) error {
|
||||
AffiliationType: affType,
|
||||
CompanyCode: compCode,
|
||||
}
|
||||
|
||||
if compCode != "" {
|
||||
if tenant, err := h.TenantService.GetTenantBySlug(c.Context(), compCode); err == nil && tenant != nil {
|
||||
resp.Tenant = tenant
|
||||
}
|
||||
}
|
||||
|
||||
return c.JSON(resp)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user