138 lines
4.5 KiB
JavaScript
138 lines
4.5 KiB
JavaScript
import { defineStore } from "pinia";
|
|
import { ref } from "vue";
|
|
import request from "@/utils/request";
|
|
import { useRouter } from "vue-router";
|
|
import { startRegistration, startAuthentication } from "@simplewebauthn/browser";
|
|
import { useAuthStore } from "./auth";
|
|
|
|
export const useWebAuthStore = defineStore("webauth", () => {
|
|
const router = useRouter();
|
|
// const token = ref(localStorage.getItem("token") || "");
|
|
|
|
const passkeys = ref(null);
|
|
|
|
const loading = ref(false);
|
|
const error = ref(null);
|
|
|
|
const addPasskey = async () => {
|
|
error.value = "";
|
|
loading.value = true;
|
|
try {
|
|
// 1. 从后端获取注册选项 (Creation Options)
|
|
const res = await request.get("/profile/passkey");
|
|
// console.log("begin:", res.data.data.publicKey);
|
|
const options = res.data.data.publicKey;
|
|
|
|
// 调用 Web Authentication API 进行注册
|
|
// const credential = await navigator.credentials.create(options);
|
|
// console.log("credential:", credential);
|
|
let attestation;
|
|
try {
|
|
// Pass 'undefined' as the second argument if you are not using an AbortSignal
|
|
attestation = await startRegistration({optionsJSON: options});
|
|
// console.log("WebAuthn 注册结果 (Attestation):", JSON.stringify(attestation));
|
|
error.value = null;
|
|
} catch (regError) {
|
|
// console.log("WebAuthn 注册失败或取消:", regError);
|
|
if (regError.name === "NotAllowedError") {
|
|
error.value = "Passkey 操作被取消或不允许。";
|
|
} else {
|
|
error.value = `Passkey 创建出错: ${regError.message}`;
|
|
}
|
|
return; // 终止流程
|
|
}
|
|
|
|
// 3. 将注册结果 (Attestation) 发送到后端进行验证和保存
|
|
const res2 = await request.post("/profile/passkey", attestation);
|
|
// console.log("end:", res2);
|
|
return res2;
|
|
} catch (err) {
|
|
error.value =err.response?.data?.error || "添加 Passkey 失败,请稍后重试。";
|
|
throw error
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const loginPasskey = async () => {
|
|
error.value = null;
|
|
loading.value = true;
|
|
try {
|
|
// 1. 从后端获取登录选项 (Assertion Options)
|
|
const res = await request.get("/auth/passkey/begin");
|
|
// console.log("login begin:", res.data);
|
|
const options = res.data.data.publicKey;
|
|
|
|
// 2. 调用 Web Authentication API 进行认证
|
|
let assertion;
|
|
try {
|
|
assertion = await startAuthentication({ optionsJSON: options });
|
|
// console.log("WebAuthn 认证结果 (Assertion):", JSON.stringify(assertion));
|
|
} catch (loginError) {
|
|
if (loginError.name === "NotAllowedError") {
|
|
error.value = "Passkey 登录被取消或不允许。";
|
|
} else {
|
|
error.value = `Passkey 登录出错: ${loginError.message}`;
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
// 3. 将认证结果 (Assertion) 发送到后端进行验证并获取 Token
|
|
const challenge = options.challenge; // 从 begin 接口返回的 options 中获取 challenge
|
|
const res2 = await request.post(`/auth/passkey/finish?challenge=${challenge}`, assertion);
|
|
|
|
// 4. 处理登录成功的响应,通常包含 Token
|
|
if (res2.status === 200 && !!res2.data.data?.token) {
|
|
const token = res2.data.data.token
|
|
const authStore = useAuthStore()
|
|
authStore.setToken(token)
|
|
await authStore.getProfile()
|
|
return res2.data
|
|
}
|
|
} catch (err) {
|
|
error.value = err.response?.data?.error || err.value || "Passkey 登录失败,请稍后重试。";
|
|
throw error;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const getPasskeys = async () => {
|
|
loading.value = true;
|
|
error.value = null;
|
|
try {
|
|
const response = await request.get('/profile/passkeys')
|
|
// console.log('getPasskeys',response.data.data)
|
|
passkeys.value = response.data.data
|
|
} catch (err) {
|
|
error.value = err.response?.data?.error || '获取token列表失败';
|
|
throw error
|
|
}finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
const deletePasskey = async (id) => {
|
|
loading.value = true;
|
|
error.value = null;
|
|
try {
|
|
const response = await request.delete(`/profile/passkeys/${id}`)
|
|
return response
|
|
} catch (err) {
|
|
error.value = err.response?.data?.error || `删除passkey ${id} 失败`;
|
|
throw error
|
|
}finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
return {
|
|
passkeys,
|
|
loading,
|
|
error,
|
|
addPasskey,
|
|
loginPasskey,
|
|
getPasskeys,
|
|
deletePasskey,
|
|
};
|
|
}); |