Erweitere die Passkey-Registrierung um Unterstützung für bevorzugte Authentifikatortypen und verbessere die Fehlerbehandlung.
This commit is contained in:
@@ -398,10 +398,53 @@ const addPasskey = async () => {
|
|||||||
passkeyLoading.value = true
|
passkeyLoading.value = true
|
||||||
try {
|
try {
|
||||||
const name = window.prompt('Name für den Passkey (z.B. "iPhone", "Laptop"):', 'Passkey') || 'Passkey'
|
const name = window.prompt('Name für den Passkey (z.B. "iPhone", "Laptop"):', 'Passkey') || 'Passkey'
|
||||||
const res = await $fetch('/api/auth/passkeys/registration-options', { method: 'POST' })
|
|
||||||
const mod = await import('@simplewebauthn/browser')
|
const mod = await import('@simplewebauthn/browser')
|
||||||
// @simplewebauthn/browser v13+ erwartet { optionsJSON: options }
|
|
||||||
const credential = await mod.startRegistration({ optionsJSON: res.options })
|
const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent || '' : ''
|
||||||
|
const isFirefox = /Firefox\//i.test(userAgent)
|
||||||
|
|
||||||
|
let platformAvailable = true
|
||||||
|
if (typeof mod.platformAuthenticatorIsAvailable === 'function') {
|
||||||
|
try {
|
||||||
|
platformAvailable = await mod.platformAuthenticatorIsAvailable()
|
||||||
|
} catch {
|
||||||
|
platformAvailable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const preferenceChain = []
|
||||||
|
if (isFirefox) {
|
||||||
|
// Firefox kann unter Linux Passkeys browserseitig verwalten, auch wenn kein
|
||||||
|
// klassischer Platform-Authenticator erkannt wird.
|
||||||
|
preferenceChain.push('localDevice', 'remoteDevice')
|
||||||
|
} else if (!platformAvailable) {
|
||||||
|
preferenceChain.push('remoteDevice', 'localDevice')
|
||||||
|
} else {
|
||||||
|
preferenceChain.push('localDevice')
|
||||||
|
}
|
||||||
|
|
||||||
|
let credential = null
|
||||||
|
let lastError = null
|
||||||
|
|
||||||
|
for (const preferredAuthenticatorType of preferenceChain) {
|
||||||
|
try {
|
||||||
|
const res = await $fetch('/api/auth/passkeys/registration-options', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { preferredAuthenticatorType }
|
||||||
|
})
|
||||||
|
|
||||||
|
// @simplewebauthn/browser v13+ erwartet { optionsJSON: options }
|
||||||
|
credential = await mod.startRegistration({ optionsJSON: res.options })
|
||||||
|
break
|
||||||
|
} catch (err) {
|
||||||
|
lastError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!credential) {
|
||||||
|
throw lastError || new Error('Passkey konnte nicht erstellt werden.')
|
||||||
|
}
|
||||||
|
|
||||||
await $fetch('/api/auth/passkeys/register', {
|
await $fetch('/api/auth/passkeys/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: { credential, name }
|
body: { credential, name }
|
||||||
@@ -409,7 +452,12 @@ const addPasskey = async () => {
|
|||||||
await loadPasskeys()
|
await loadPasskeys()
|
||||||
successMessage.value = 'Passkey hinzugefügt.'
|
successMessage.value = 'Passkey hinzugefügt.'
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
passkeyError.value = e?.data?.message || e?.message || 'Passkey konnte nicht hinzugefügt werden.'
|
const rawMessage = e?.data?.message || e?.message || ''
|
||||||
|
if (String(rawMessage).includes('NotAllowedError')) {
|
||||||
|
passkeyError.value = 'Passkey-Erstellung abgebrochen oder nicht erlaubt. Unter Firefox/Linux ggf. Smartphone-Passkey oder Sicherheitsschlüssel verwenden.'
|
||||||
|
} else {
|
||||||
|
passkeyError.value = rawMessage || 'Passkey konnte nicht hinzugefügt werden.'
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
passkeyLoading.value = false
|
passkeyLoading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ export default defineEventHandler(async (event) => {
|
|||||||
return { success: true }
|
return { success: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const body = await readBody(event)
|
||||||
|
const preferredAuthenticatorType = ['securityKey', 'localDevice', 'remoteDevice'].includes(body?.preferredAuthenticatorType)
|
||||||
|
? body.preferredAuthenticatorType
|
||||||
|
: undefined
|
||||||
|
|
||||||
const token = getCookie(event, 'auth_token')
|
const token = getCookie(event, 'auth_token')
|
||||||
const user = token ? await getUserFromToken(token) : null
|
const user = token ? await getUserFromToken(token) : null
|
||||||
|
|
||||||
@@ -64,6 +69,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
// authenticatorAttachment weglassen = beide Typen erlauben (platform + cross-platform)
|
// authenticatorAttachment weglassen = beide Typen erlauben (platform + cross-platform)
|
||||||
},
|
},
|
||||||
excludeCredentials,
|
excludeCredentials,
|
||||||
|
preferredAuthenticatorType,
|
||||||
// Timeout erhöhen für Cross-Device (Standard: 60s, hier: 5 Minuten)
|
// Timeout erhöhen für Cross-Device (Standard: 60s, hier: 5 Minuten)
|
||||||
timeout: 300000
|
timeout: 300000
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user