1
0
forked from baron/baron-sso

feat: restore explicit loginId field and add to userfront signup flow

- Revert the removal of loginId from adminfront and backend.
- Prevent phone normalization logic from mangling custom employee ID login fields.
- Add an explicit 'loginId' optional input field to the userfront signup UI.
- Update AuthProxyService.signup and backend AuthHandler.Signup to transmit and map the 'loginId' parameter properly.
This commit is contained in:
2026-03-26 14:22:43 +09:00
parent 85b2049a61
commit aa60a22d57
4 changed files with 33 additions and 6 deletions

View File

@@ -451,8 +451,23 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
// grade는 기존 스키마 필수 키이므로 기본값을 설정 // grade는 기존 스키마 필수 키이므로 기본값을 설정
"grade": "member", "grade": "member",
} }
if req.LoginID != "" {
attributes["id"] = req.LoginID
}
// Sync custom field to LoginID if configured
if tenantID != nil && h.TenantService != nil {
if tenant, err := h.TenantService.GetTenant(c.Context(), *tenantID); err == nil && tenant != nil {
if loginIdField, ok := tenant.Config["loginIdField"].(string); ok && loginIdField != "" {
syncLoginID(attributes, req.Metadata, *tenantID, loginIdField)
}
}
}
brokerUser := &domain.BrokerUser{ brokerUser := &domain.BrokerUser{
Email: req.Email, Email: req.Email,
LoginID: extractTraitString(attributes, "id"),
Name: req.Name, Name: req.Name,
PhoneNumber: normalizedPhone, PhoneNumber: normalizedPhone,
Attributes: attributes, Attributes: attributes,

View File

@@ -1533,12 +1533,6 @@ func syncLoginID(traits map[string]interface{}, metadata map[string]any, tenantI
} }
if loginID != "" { if loginID != "" {
// Normalize if it looks like a phone number to be consistent with other identifiers
normalized := normalizePhoneNumber(loginID)
if normalized != "" {
loginID = normalized
}
slog.Info("Syncing LoginID from custom field", "field", loginIDField, "value", loginID, "tenantID", tenantID) slog.Info("Syncing LoginID from custom field", "field", loginIDField, "value", loginID, "tenantID", tenantID)
traits["id"] = loginID traits["id"] = loginID
} }

View File

@@ -934,6 +934,7 @@ class AuthProxyService {
static Future<void> signup({ static Future<void> signup({
required String email, required String email,
String? loginId,
required String password, required String password,
required String name, required String name,
required String phone, required String phone,
@@ -949,6 +950,7 @@ class AuthProxyService {
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: jsonEncode({ body: jsonEncode({
'email': email, 'email': email,
if (loginId != null && loginId.isNotEmpty) 'loginId': loginId,
'password': password, 'password': password,
'name': name, 'name': name,
'phone': phone, 'phone': phone,

View File

@@ -31,6 +31,7 @@ class _SignupScreenState extends State<SignupScreen> {
// Controllers // Controllers
final _emailController = TextEditingController(); final _emailController = TextEditingController();
final _loginIdController = TextEditingController();
final _emailCodeController = TextEditingController(); final _emailCodeController = TextEditingController();
final _phoneController = TextEditingController(); final _phoneController = TextEditingController();
final _phoneCodeController = TextEditingController(); final _phoneCodeController = TextEditingController();
@@ -98,6 +99,7 @@ class _SignupScreenState extends State<SignupScreen> {
_emailTimer?.cancel(); _emailTimer?.cancel();
_phoneTimer?.cancel(); _phoneTimer?.cancel();
_emailController.dispose(); _emailController.dispose();
_loginIdController.dispose();
_emailCodeController.dispose(); _emailCodeController.dispose();
_phoneController.dispose(); _phoneController.dispose();
_phoneCodeController.dispose(); _phoneCodeController.dispose();
@@ -311,6 +313,7 @@ class _SignupScreenState extends State<SignupScreen> {
try { try {
await AuthProxyService.signup( await AuthProxyService.signup(
email: _emailController.text.trim(), email: _emailController.text.trim(),
loginId: _loginIdController.text.trim(),
password: _passwordController.text, password: _passwordController.text,
name: _nameController.text.trim(), name: _nameController.text.trim(),
phone: _phoneController.text.trim(), phone: _phoneController.text.trim(),
@@ -1421,6 +1424,19 @@ class _SignupScreenState extends State<SignupScreen> {
), ),
), ),
const SizedBox(height: 18), const SizedBox(height: 18),
_buildProfileFieldGroup(
title: '로그인 ID (선택)',
description: '이메일/전화번호 외에 별도의 식별자로 로그인할 때 사용합니다.',
isDesktop: isDesktop,
child: TextFormField(
controller: _loginIdController,
decoration: const InputDecoration(
labelText: '사번 또는 아이디',
border: OutlineInputBorder(),
),
),
),
const SizedBox(height: 18),
_buildProfileFieldGroup( _buildProfileFieldGroup(
title: tr('ui.userfront.signup.profile.affiliation_type'), title: tr('ui.userfront.signup.profile.affiliation_type'),
description: _isAffiliateEmail description: _isAffiliateEmail