feat(auth): 实现基于Passkey的登录功能
- 添加了对Web Credentials API的支持- 实现了Passkey注册与认证流程 - 引入了TDesign Button组件用于登录按钮 - 更新了页面加载及过渡动画逻辑- 添加了对不支持Passkey设备的降级处理 - 安装并配置了tdesign-icons-vue-next依赖库
This commit is contained in:
parent
a2ab4b8bb3
commit
5abf344572
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -20,5 +20,6 @@ declare module 'vue' {
|
|||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
TAvatar: typeof import('tdesign-mobile-vue')['Avatar']
|
TAvatar: typeof import('tdesign-mobile-vue')['Avatar']
|
||||||
|
TButton: typeof import('tdesign-mobile-vue')['Button']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
package-lock.json
generated
1
package-lock.json
generated
@ -12,6 +12,7 @@
|
|||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"sass-loader": "^16.0.6",
|
"sass-loader": "^16.0.6",
|
||||||
"scss": "^0.2.4",
|
"scss": "^0.2.4",
|
||||||
|
"tdesign-icons-vue-next": "^0.4.1",
|
||||||
"tdesign-mobile-vue": "^1.11.0",
|
"tdesign-mobile-vue": "^1.11.0",
|
||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
"vue-router": "^4.6.3"
|
"vue-router": "^4.6.3"
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"sass-loader": "^16.0.6",
|
"sass-loader": "^16.0.6",
|
||||||
"scss": "^0.2.4",
|
"scss": "^0.2.4",
|
||||||
|
"tdesign-icons-vue-next": "^0.4.1",
|
||||||
"tdesign-mobile-vue": "^1.11.0",
|
"tdesign-mobile-vue": "^1.11.0",
|
||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
"vue-router": "^4.6.3"
|
"vue-router": "^4.6.3"
|
||||||
|
|||||||
65
src/App.vue
65
src/App.vue
@ -5,22 +5,24 @@
|
|||||||
<span v-if="showTitle" class="title">你好,{{ name }}</span>
|
<span v-if="showTitle" class="title">你好,{{ name }}</span>
|
||||||
</transition>
|
</transition>
|
||||||
<div class="login-info">
|
<div class="login-info">
|
||||||
<transition name="slide-up">
|
<transition name="slide-up" mode="out-in">
|
||||||
<div v-if="!weCome">
|
<div v-if="!login">
|
||||||
|
<t-button :disabled="!passkey" @click="handleLogin">登录</t-button>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="!weCome">
|
||||||
<transition name="slide-up" mode="out-in">
|
<transition name="slide-up" mode="out-in">
|
||||||
<div v-if="!login">
|
<div v-if="login">
|
||||||
<div class="loading" />
|
<div class="loading" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else>你好,{{ name }}</div>
|
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="header-placeholder"/>
|
<div class="header-placeholder" />
|
||||||
|
|
||||||
<div id="operable-box">
|
<div id="operable-box">
|
||||||
<RouterView v-if="login" ref="routerView" #default="{ Component }">
|
<RouterView v-if="login" #default="{ Component }">
|
||||||
<transition name="slide-up" mode="out-in">
|
<transition name="slide-up" mode="out-in">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</transition>
|
</transition>
|
||||||
@ -33,16 +35,49 @@ import { RouterView } from 'vue-router'
|
|||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import avatar from '@/assets/logo.svg'
|
import avatar from '@/assets/logo.svg'
|
||||||
|
|
||||||
const login = ref(true)
|
const login = ref(false)
|
||||||
const weCome = ref(true)
|
const weCome = ref(false)
|
||||||
const hideLoading = ref(true)
|
const hideLoading = ref(false)
|
||||||
const showTitle = ref(true)
|
const showTitle = ref(false)
|
||||||
|
|
||||||
|
const passkey = ref(true)
|
||||||
const name = ref('Amico')
|
const name = ref('Amico')
|
||||||
// mock login
|
|
||||||
setTimeout(() => {
|
if (!navigator.credentials) {
|
||||||
login.value = true
|
passkey.value = false
|
||||||
}, 1000)
|
}
|
||||||
const routerView = ref()
|
|
||||||
|
function handleLogin(){
|
||||||
|
navigator.credentials.create({
|
||||||
|
publicKey: {
|
||||||
|
challenge: new Uint8Array(32),
|
||||||
|
timeout: 60000,
|
||||||
|
rp: {
|
||||||
|
id: window.location.host,
|
||||||
|
name: "Animo"
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: new Uint8Array(32),
|
||||||
|
name: "Amico",
|
||||||
|
displayName: "Amico",
|
||||||
|
},
|
||||||
|
pubKeyCredParams: [{
|
||||||
|
alg: -7, type: "public-key"
|
||||||
|
},{
|
||||||
|
alg: -257, type: "public-key"
|
||||||
|
}],
|
||||||
|
excludeCredentials: [],
|
||||||
|
authenticatorSelection: {
|
||||||
|
authenticatorAttachment: "platform",
|
||||||
|
requireResidentKey: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}).then(resp => {
|
||||||
|
login.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录动画流程
|
||||||
watch(login, (val) => {
|
watch(login, (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user