diff --git a/service/passkey/service.go b/service/passkey/service.go index 62befb9d3..dc8da0ccc 100644 --- a/service/passkey/service.go +++ b/service/passkey/service.go @@ -80,9 +80,11 @@ func BuildWebAuthn(r *http.Request) (*webauthn.WebAuthn, error) { } func resolveOrigins(r *http.Request, settings *system_setting.PasskeySettings) ([]string, error) { - if len(settings.Origins) > 0 { - origins := make([]string, 0, len(settings.Origins)) - for _, origin := range settings.Origins { + originsStr := strings.TrimSpace(settings.Origins) + if originsStr != "" { + originList := strings.Split(originsStr, ",") + origins := make([]string, 0, len(originList)) + for _, origin := range originList { trimmed := strings.TrimSpace(origin) if trimmed == "" { continue diff --git a/setting/system_setting/passkey.go b/setting/system_setting/passkey.go index 54746e808..63e4756b4 100644 --- a/setting/system_setting/passkey.go +++ b/setting/system_setting/passkey.go @@ -1,25 +1,27 @@ package system_setting import ( + "net/url" "one-api/common" "one-api/setting/config" + "strings" ) type PasskeySettings struct { - Enabled bool `json:"enabled"` - RPDisplayName string `json:"rp_display_name"` - RPID string `json:"rp_id"` - Origins []string `json:"origins"` - AllowInsecureOrigin bool `json:"allow_insecure_origin"` - UserVerification string `json:"user_verification"` - AttachmentPreference string `json:"attachment_preference"` + Enabled bool `json:"enabled"` + RPDisplayName string `json:"rp_display_name"` + RPID string `json:"rp_id"` + Origins string `json:"origins"` + AllowInsecureOrigin bool `json:"allow_insecure_origin"` + UserVerification string `json:"user_verification"` + AttachmentPreference string `json:"attachment_preference"` } var defaultPasskeySettings = PasskeySettings{ Enabled: false, RPDisplayName: common.SystemName, RPID: "", - Origins: []string{}, + Origins: "", AllowInsecureOrigin: false, UserVerification: "preferred", AttachmentPreference: "", @@ -30,5 +32,15 @@ func init() { } func GetPasskeySettings() *PasskeySettings { + if defaultPasskeySettings.RPID == "" && ServerAddress != "" { + // 从ServerAddress提取域名作为RPID + // ServerAddress可能是 "https://newapi.pro" 这种格式 + serverAddr := strings.TrimSpace(ServerAddress) + if parsed, err := url.Parse(serverAddr); err == nil && parsed.Host != "" { + defaultPasskeySettings.RPID = parsed.Host + } else { + defaultPasskeySettings.RPID = serverAddr + } + } return &defaultPasskeySettings } diff --git a/web/src/components/settings/SystemSetting.jsx b/web/src/components/settings/SystemSetting.jsx index f0c2dbc3a..b5a892864 100644 --- a/web/src/components/settings/SystemSetting.jsx +++ b/web/src/components/settings/SystemSetting.jsx @@ -122,7 +122,6 @@ const SystemSetting = () => { const [domainList, setDomainList] = useState([]); const [ipList, setIpList] = useState([]); const [allowedPorts, setAllowedPorts] = useState([]); - const [passkeyOrigins, setPasskeyOrigins] = useState([]); const getOptions = async () => { setLoading(true); @@ -188,22 +187,19 @@ const SystemSetting = () => { item.value = toBoolean(item.value); break; case 'passkey.origins': - try { - const origins = item.value ? JSON.parse(item.value) : []; - setPasskeyOrigins(Array.isArray(origins) ? origins : []); - item.value = Array.isArray(origins) ? origins : []; - } catch (e) { - setPasskeyOrigins([]); - item.value = []; - } + // origins是逗号分隔的字符串,直接使用 + item.value = item.value || ''; break; case 'passkey.rp_display_name': case 'passkey.rp_id': - case 'passkey.user_verification': case 'passkey.attachment_preference': // 确保字符串字段不为null/undefined item.value = item.value || ''; break; + case 'passkey.user_verification': + // 确保有默认值 + item.value = item.value || 'preferred'; + break; case 'Price': case 'MinTopUp': item.value = parseFloat(item.value); @@ -611,42 +607,33 @@ const SystemSetting = () => { }; const submitPasskeySettings = async () => { + // 使用formApi直接获取当前表单值 + const formValues = formApiRef.current?.getValues() || {}; + const options = []; - // 只在值有变化时才提交,并确保空值转换为空字符串 - if (originInputs['passkey.rp_display_name'] !== inputs['passkey.rp_display_name']) { - options.push({ - key: 'passkey.rp_display_name', - value: inputs['passkey.rp_display_name'] || '', - }); - } - if (originInputs['passkey.rp_id'] !== inputs['passkey.rp_id']) { - options.push({ - key: 'passkey.rp_id', - value: inputs['passkey.rp_id'] || '', - }); - } - if (originInputs['passkey.user_verification'] !== inputs['passkey.user_verification']) { - options.push({ - key: 'passkey.user_verification', - value: inputs['passkey.user_verification'] || 'preferred', - }); - } - if (originInputs['passkey.attachment_preference'] !== inputs['passkey.attachment_preference']) { - options.push({ - key: 'passkey.attachment_preference', - value: inputs['passkey.attachment_preference'] || '', - }); - } - // Origins总是提交,因为它们可能会被用户清空 + options.push({ + key: 'passkey.rp_display_name', + value: formValues['passkey.rp_display_name'] || inputs['passkey.rp_display_name'] || '', + }); + options.push({ + key: 'passkey.rp_id', + value: formValues['passkey.rp_id'] || inputs['passkey.rp_id'] || '', + }); + options.push({ + key: 'passkey.user_verification', + value: formValues['passkey.user_verification'] || inputs['passkey.user_verification'] || 'preferred', + }); + options.push({ + key: 'passkey.attachment_preference', + value: formValues['passkey.attachment_preference'] || inputs['passkey.attachment_preference'] || '', + }); options.push({ key: 'passkey.origins', - value: JSON.stringify(Array.isArray(passkeyOrigins) ? passkeyOrigins : []), + value: formValues['passkey.origins'] || inputs['passkey.origins'] || '', }); - if (options.length > 0) { - await updateOptions(options); - } + await updateOptions(options); }; const handleCheckboxChange = async (optionKey, event) => { @@ -1037,7 +1024,7 @@ const SystemSetting = () => { > handleCheckboxChange('passkey.enabled', e) @@ -1052,7 +1039,7 @@ const SystemSetting = () => { > { { > { { > @@ -1120,21 +1107,11 @@ const SystemSetting = () => { style={{ marginTop: 16 }} > - {t('允许的 Origins')} - - {t('留空将自动使用服务器地址,多个 Origin 用于支持多域名部署')} - - { - setPasskeyOrigins(value); - setInputs(prev => ({ - ...prev, - 'passkey.origins': value - })); - }} - placeholder={t('输入 Origin 后回车,如:https://example.com')} - style={{ width: '100%' }} +