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:
@@ -94,4 +94,54 @@ func TestUserRepository(t *testing.T) {
|
||||
assert.Equal(t, int64(1), counts["tenant-b"])
|
||||
assert.Equal(t, int64(0), counts["tenant-c"])
|
||||
})
|
||||
|
||||
t.Run("Multi-Identifier Support", func(t *testing.T) {
|
||||
_ = testDB.AutoMigrate(&domain.UserLoginID{})
|
||||
testDB.Exec("DELETE FROM user_login_ids")
|
||||
testDB.Exec("DELETE FROM users")
|
||||
|
||||
user := &domain.User{Email: "multi@test.com", Name: "Multi"}
|
||||
_ = repo.Create(ctx, user)
|
||||
|
||||
t1 := "00000000-0000-0000-0000-000000000001"
|
||||
t2 := "00000000-0000-0000-0000-000000000002"
|
||||
|
||||
loginIDs := []domain.UserLoginID{
|
||||
{UserID: user.ID, TenantID: t1, FieldKey: "emp_id", LoginID: "E001"},
|
||||
{UserID: user.ID, TenantID: t2, FieldKey: "student_id", LoginID: "S001"},
|
||||
}
|
||||
|
||||
err := repo.UpdateUserLoginIDs(ctx, user.ID, loginIDs)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get and Verify
|
||||
saved, err := repo.GetUserLoginIDs(ctx, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, saved, 2)
|
||||
|
||||
// IsLoginIDTaken
|
||||
taken, err := repo.IsLoginIDTaken(ctx, "E001")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, taken)
|
||||
|
||||
taken, err = repo.IsLoginIDTaken(ctx, "UNKNOWN")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, taken)
|
||||
|
||||
// FindTenantIDByLoginID
|
||||
tid, err := repo.FindTenantIDByLoginID(ctx, "S001")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, t2, tid)
|
||||
|
||||
// Update (Replace)
|
||||
newList := []domain.UserLoginID{
|
||||
{UserID: user.ID, TenantID: t1, FieldKey: "emp_id", LoginID: "E002"},
|
||||
}
|
||||
err = repo.UpdateUserLoginIDs(ctx, user.ID, newList)
|
||||
assert.NoError(t, err)
|
||||
|
||||
saved, _ = repo.GetUserLoginIDs(ctx, user.ID)
|
||||
assert.Len(t, saved, 1)
|
||||
assert.Equal(t, "E002", saved[0].LoginID)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user