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:
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user