update
This commit is contained in:
@@ -65,6 +65,7 @@ interface AuthState {
|
||||
publicCaptchaConfig: PublicCaptchaConfig | null; // NEW: Public CAPTCHA config
|
||||
passkeys: PasskeyInfo[] | null; // NEW: Store for user's passkeys
|
||||
passkeysLoading: boolean; // NEW: Loading state for passkeys
|
||||
hasPasskeysAvailable: boolean; // NEW: Indicates if passkeys are available for login
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
@@ -79,6 +80,7 @@ export const useAuthStore = defineStore('auth', {
|
||||
publicCaptchaConfig: null, // NEW: Initialize CAPTCHA config as null
|
||||
passkeys: null, // Initialize passkeys as null
|
||||
passkeysLoading: false, // Initialize passkeysLoading as false
|
||||
hasPasskeysAvailable: false, // Initialize as false
|
||||
}),
|
||||
getters: {
|
||||
// 可以添加一些 getter,例如获取用户名
|
||||
@@ -505,6 +507,23 @@ export const useAuthStore = defineStore('auth', {
|
||||
// if using specific loading state: this.passkeyNameUpdateLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// Action to check if passkeys are configured (for login page)
|
||||
async checkHasPasskeysConfigured(username?: string) {
|
||||
// This action should not set isLoading to true, as it's a quick check
|
||||
// and primarily used to determine UI elements on the login page.
|
||||
try {
|
||||
const params = username ? { username } : {};
|
||||
const response = await apiClient.get<{ hasPasskeys: boolean }>('/auth/passkey/has-configured', { params });
|
||||
this.hasPasskeysAvailable = response.data.hasPasskeys;
|
||||
console.log(`[AuthStore] Passkeys available for ${username || 'any user'}: ${this.hasPasskeysAvailable}`);
|
||||
return this.hasPasskeysAvailable;
|
||||
} catch (error: any) {
|
||||
console.error('Failed to check if passkeys are configured:', error.response?.data?.message || error.message);
|
||||
this.hasPasskeysAvailable = false; // Default to false on error
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
persist: true, // Revert to simple persistence to fix TS error for now
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import VueRecaptcha from 'vue3-recaptcha2'; // 使用默认导入
|
||||
const { t } = useI18n();
|
||||
const authStore = useAuthStore();
|
||||
// 获取 loginRequires2FA 状态
|
||||
const { isLoading, error, loginRequires2FA, publicCaptchaConfig, passkeys } = storeToRefs(authStore); // Get publicCaptchaConfig and passkeys
|
||||
const { isLoading, error, loginRequires2FA, publicCaptchaConfig, hasPasskeysAvailable } = storeToRefs(authStore); // Get publicCaptchaConfig and hasPasskeysAvailable
|
||||
|
||||
// 表单数据
|
||||
const credentials = reactive({
|
||||
@@ -92,10 +92,13 @@ const handleSubmit = async () => {
|
||||
} // <-- Correctly closing the try block here
|
||||
};
|
||||
|
||||
// Fetch CAPTCHA config on component mount
|
||||
onMounted(() => {
|
||||
// console.log('[LoginView] Component mounted, calling fetchCaptchaConfig...'); // 添加日志
|
||||
// Fetch CAPTCHA config and check passkey availability on component mount
|
||||
onMounted(async () => {
|
||||
// console.log('[LoginView] Component mounted, calling fetchCaptchaConfig and checkHasPasskeysConfigured...');
|
||||
authStore.fetchCaptchaConfig();
|
||||
// Check if passkeys are available for login (uses the new public endpoint)
|
||||
// Optionally pass username if needed: await authStore.checkHasPasskeysConfigured(credentials.username);
|
||||
await authStore.checkHasPasskeysConfigured();
|
||||
});
|
||||
|
||||
// --- Passkey Login Handler ---
|
||||
@@ -243,7 +246,7 @@ const handlePasskeyLogin = async () => {
|
||||
</button>
|
||||
|
||||
<!-- Passkey Login Button -->
|
||||
<div v-if="passkeys && passkeys.length > 0" class="mt-4 text-center">
|
||||
<div v-if="hasPasskeysAvailable" class="mt-4 text-center">
|
||||
<button type="button" @click="handlePasskeyLogin" :disabled="isLoading"
|
||||
class="w-full py-3 px-4 bg-secondary text-black border-none rounded-lg text-base font-semibold cursor-pointer shadow-md transition-colors duration-200 ease-in-out hover:bg-secondary-dark focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-secondary disabled:bg-gray-400 disabled:cursor-not-allowed disabled:opacity-70 flex items-center justify-center">
|
||||
<i class="fas fa-key mr-2"></i>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<span class="text-xs text-text-tertiary ml-1">(ID: ...{{ typeof key.credentialID === 'string' && key.credentialID ? key.credentialID.slice(-8) : 'N/A' }})</span>
|
||||
</span>
|
||||
<div v-else class="flex items-center flex-grow">
|
||||
<input type="text" v-model="editingPasskeyName" @keyup.enter="savePasskeyName(key.credentialID)" @keyup.esc="cancelEditPasskeyName" class="flex-grow max-w-sm px-2 py-1 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary text-sm" :placeholder="$t('settings.passkey.enterNamePlaceholder', '输入 Passkey 名称')" />
|
||||
<input type="text" v-model="editingPasskeyName" @keyup.enter="savePasskeyName(key.credentialID)" @keyup.esc="cancelEditPasskeyName" class="flex-grow w-48 px-2 py-1 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary text-sm" :placeholder="$t('settings.passkey.enterNamePlaceholder', '输入 Passkey 名称')" />
|
||||
<button @click="savePasskeyName(key.credentialID)" :disabled="passkeyEditLoadingStates[key.credentialID]" class="ml-2 px-2 py-1 bg-success text-success-text rounded-md text-xs font-medium hover:bg-success/80 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-success disabled:opacity-50 disabled:cursor-not-allowed transition duration-150 ease-in-out">
|
||||
{{ passkeyEditLoadingStates[key.credentialID] ? $t('common.saving') : $t('common.save') }}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user