- 引入 go-webauthn, Passkey 表存凭据, challenge 会话内存存储(带过期) - API: /webauthn/register|login begin/complete, /webauthn/passkeys 列表/删除 - 配置 OT_WEBAUTHN_RP_ID/RP_ORIGIN/RP_NAME;登录成功发 JWT+refresh cookie - 前端 lib/webauthn(编解码+凭据序列化+安全上下文检测), 账户设置绑定区, 登录页免密按钮 - 需 HTTPS 或 localhost(安全上下文) Co-Authored-By: Claude <noreply@anthropic.com>
63 lines
1.7 KiB
TypeScript
63 lines
1.7 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { http } from '@/api/client'
|
|
import type { User } from '@/types'
|
|
|
|
export const useAuthStore = defineStore('auth', {
|
|
state: () => ({
|
|
user: null as User | null,
|
|
accessToken: localStorage.getItem('ot_access') ?? '',
|
|
ready: false,
|
|
}),
|
|
getters: {
|
|
isAuthed: (s) => !!s.accessToken && !!s.user,
|
|
isAdmin: (s) => s.user?.role === 'admin',
|
|
},
|
|
actions: {
|
|
async bootstrap() {
|
|
try {
|
|
if (!this.accessToken) {
|
|
await this.refresh()
|
|
}
|
|
await this.fetchMe()
|
|
} catch {
|
|
this.clear()
|
|
}
|
|
this.ready = true
|
|
},
|
|
async register(username: string, email: string, password: string) {
|
|
await http.post('/auth/register', { username, email, password })
|
|
},
|
|
async login(username: string, password: string) {
|
|
const { data } = await http.post('/auth/login', { username, password })
|
|
this.setSession(data.data)
|
|
},
|
|
setSession(d: { access_token: string; user: User }) {
|
|
this.accessToken = d.access_token
|
|
this.user = d.user
|
|
localStorage.setItem('ot_access', d.access_token)
|
|
},
|
|
async refresh() {
|
|
const { data } = await http.post('/auth/refresh')
|
|
this.accessToken = data.data.access_token as string
|
|
localStorage.setItem('ot_access', this.accessToken)
|
|
},
|
|
async fetchMe() {
|
|
const { data } = await http.get('/auth/me')
|
|
this.user = data.data.user as User
|
|
},
|
|
async logout() {
|
|
try {
|
|
await http.post('/auth/logout')
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
this.clear()
|
|
},
|
|
clear() {
|
|
this.accessToken = ''
|
|
this.user = null
|
|
localStorage.removeItem('ot_access')
|
|
},
|
|
},
|
|
})
|