Integrate passkey authentication and management
- Added passkey support for secure, passwordless authentication using WebAuthn. - Implemented passkey management in user profiles, enabling users to add, rename, and delete passkeys. - Updated authentication forms to support passkey login, including feature detection and login flow. - Enhanced internationalization files with passkey-related translations for multiple locales. - Introduced new components and services for handling passkey operations and WebAuthn interactions.
This commit is contained in:
@@ -1,12 +1,21 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { parseError, getError } from "@/components/request/HandleGlobalError.vue";
|
||||
import { parseError, getError, addError } from "@/components/request/HandleGlobalError.vue";
|
||||
import LoadButtonWhileAwait from "@/components/request/LoadButtonWhileAwait.vue";
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
import { isPasskeySupported, authenticateWithPasskey } from "@/services/PasskeyAuthService.js";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// Passkey support
|
||||
const passkeySupported = ref(false);
|
||||
const isPasskeyLoading = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
passkeySupported.value = isPasskeySupported();
|
||||
});
|
||||
|
||||
// Login method selection
|
||||
const loginMethod = ref('phone'); // 'phone' or 'username'
|
||||
|
||||
@@ -43,6 +52,23 @@ const login = async () => {
|
||||
const doNothing = () => {
|
||||
// Prevent form submission
|
||||
};
|
||||
|
||||
// Passkey login
|
||||
const loginWithPasskey = async () => {
|
||||
isPasskeyLoading.value = true;
|
||||
try {
|
||||
const result = await authenticateWithPasskey('subuser');
|
||||
if (result.token) {
|
||||
localStorage.setItem('token', result.token);
|
||||
// Reload the page to update the UI
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (e) {
|
||||
addError('auth', e.message || t('passkeys.login_failed'));
|
||||
} finally {
|
||||
isPasskeyLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -114,6 +140,24 @@ const doNothing = () => {
|
||||
<LoadButtonWhileAwait :loadFunction="login" class="submit" id="subuser-login-button">
|
||||
{{ t('auth.login') }}
|
||||
</LoadButtonWhileAwait>
|
||||
|
||||
<!-- Passkey login button -->
|
||||
<button
|
||||
v-if="passkeySupported"
|
||||
type="button"
|
||||
class="submit passkey-btn"
|
||||
@click="loginWithPasskey"
|
||||
:disabled="isPasskeyLoading"
|
||||
id="subuser-passkey-login-button"
|
||||
>
|
||||
<span class="icon" v-if="!isPasskeyLoading">
|
||||
<i class="fas fa-fingerprint"></i>
|
||||
</span>
|
||||
<span class="icon" v-else>
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
</span>
|
||||
<span>{{ t('passkeys.login_with_passkey') }}</span>
|
||||
</button>
|
||||
|
||||
<router-link :to="{name: 'login'}" class="link">{{ t('auth.login_as_customer') }}</router-link>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user