forked from baron/baron-sso
feat: implement multi-identifier architecture (Issue #496)
- Database: Add user_login_ids table for 1:N identifier mapping and remove legacy login_id column - Kratos: Update identity schema to use custom_login_ids array instead of a single id trait - Backend: Implement syncCustomLoginIDs to collect isLoginId fields across tenant schemas - Backend: Add backtracking logic to auto-assign session tenant based on used login identifier - Backend: Add 409 Conflict exception handling for Create/Update operations - AdminFront: Refactor UserDetailPage to a tabbed grid layout (Info, Tenants, Security) - AdminFront: Show '로그인 ID' badge on tenant schema fields used for authentication - UserFront: Remove legacy optional 'Login ID' input from signup flow - Tests: Add multi-identifier repository tests and update handler tests
This commit is contained in:
@@ -21,6 +21,12 @@ type UserRepository interface {
|
||||
CountByTenantIDs(ctx context.Context, tenantIDs []string) (map[string]int64, error)
|
||||
CountByCompanyCodes(ctx context.Context, codes []string) (map[string]int64, error)
|
||||
Delete(ctx context.Context, id string) error
|
||||
|
||||
// Multiple identifiers support
|
||||
UpdateUserLoginIDs(ctx context.Context, userID string, loginIDs []domain.UserLoginID) error
|
||||
GetUserLoginIDs(ctx context.Context, userID string) ([]domain.UserLoginID, error)
|
||||
IsLoginIDTaken(ctx context.Context, loginID string) (bool, error)
|
||||
FindTenantIDByLoginID(ctx context.Context, loginID string) (string, error)
|
||||
}
|
||||
|
||||
type userRepository struct {
|
||||
@@ -193,3 +199,45 @@ func (r *userRepository) List(ctx context.Context, offset, limit int, search str
|
||||
func (r *userRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.db.WithContext(ctx).Delete(&domain.User{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
func (r *userRepository) UpdateUserLoginIDs(ctx context.Context, userID string, loginIDs []domain.UserLoginID) error {
|
||||
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
// Delete existing login IDs for this user
|
||||
if err := tx.Where("user_id = ?", userID).Delete(&domain.UserLoginID{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert new login IDs if any
|
||||
if len(loginIDs) > 0 {
|
||||
if err := tx.Create(&loginIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (r *userRepository) GetUserLoginIDs(ctx context.Context, userID string) ([]domain.UserLoginID, error) {
|
||||
var results []domain.UserLoginID
|
||||
if err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&results).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *userRepository) IsLoginIDTaken(ctx context.Context, loginID string) (bool, error) {
|
||||
var count int64
|
||||
if err := r.db.WithContext(ctx).Model(&domain.UserLoginID{}).Where("login_id = ?", loginID).Count(&count).Error; err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (r *userRepository) FindTenantIDByLoginID(ctx context.Context, loginID string) (string, error) {
|
||||
var record domain.UserLoginID
|
||||
if err := r.db.WithContext(ctx).Where("login_id = ?", loginID).First(&record).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
return record.TenantID, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user