mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
enhance: user token storage
This commit is contained in:
parent
925e61abf4
commit
59947a35db
5 changed files with 66 additions and 48 deletions
|
@ -46,7 +46,7 @@ async function passkeyAuthenticate() {
|
||||||
passkeyLoading.value = true
|
passkeyLoading.value = true
|
||||||
try {
|
try {
|
||||||
const begin = await twoFA.begin_start_secure_session_by_passkey()
|
const begin = await twoFA.begin_start_secure_session_by_passkey()
|
||||||
const asseResp = await startAuthentication(begin.options.publicKey)
|
const asseResp = await startAuthentication({ optionsJSON: begin.options.publicKey })
|
||||||
|
|
||||||
const r = await twoFA.finish_start_secure_session_by_passkey({
|
const r = await twoFA.finish_start_secure_session_by_passkey({
|
||||||
session_id: begin.session_id,
|
session_id: begin.session_id,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { createVNode, render } from 'vue'
|
import { createVNode, render } from 'vue'
|
||||||
import { Modal, message } from 'ant-design-vue'
|
import { Modal, message } from 'ant-design-vue'
|
||||||
import { useCookies } from '@vueuse/integrations/useCookies'
|
|
||||||
import Authorization from '@/components/TwoFA/Authorization.vue'
|
import Authorization from '@/components/TwoFA/Authorization.vue'
|
||||||
import twoFA from '@/api/2fa'
|
import twoFA from '@/api/2fa'
|
||||||
import { useUserStore } from '@/pinia'
|
import { useUserStore } from '@/pinia'
|
||||||
|
@ -32,11 +31,8 @@ const use2FAModal = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const cookies = useCookies(['nginx-ui-2fa'])
|
if (secureSessionId.value && secureSessionStatus) {
|
||||||
const ssid = cookies.get('secure_session_id')
|
resolve(secureSessionId.value)
|
||||||
if (ssid && secureSessionStatus) {
|
|
||||||
resolve(ssid)
|
|
||||||
secureSessionId.value = ssid
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -51,7 +47,6 @@ const use2FAModal = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSessionId = (sessionId: string) => {
|
const setSessionId = (sessionId: string) => {
|
||||||
cookies.set('secure_session_id', sessionId, { maxAge: 60 * 3 })
|
|
||||||
close()
|
close()
|
||||||
secureSessionId.value = sessionId
|
secureSessionId.value = sessionId
|
||||||
resolve(sessionId)
|
resolve(sessionId)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { AxiosRequestConfig } from 'axios'
|
import type { AxiosRequestConfig } from 'axios'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { useCookies } from '@vueuse/integrations/useCookies'
|
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import NProgress from 'nprogress'
|
import NProgress from 'nprogress'
|
||||||
import { useSettingsStore, useUserStore } from '@/pinia'
|
import { useSettingsStore, useUserStore } from '@/pinia'
|
||||||
|
@ -62,10 +61,9 @@ instance.interceptors.response.use(
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
|
|
||||||
const otpModal = use2FAModal()
|
const otpModal = use2FAModal()
|
||||||
const cookies = useCookies(['nginx-ui-2fa'])
|
|
||||||
switch (error.response.status) {
|
switch (error.response.status) {
|
||||||
case 401:
|
case 401:
|
||||||
cookies.remove('secure_session_id')
|
secureSessionId.value = ''
|
||||||
await otpModal.open()
|
await otpModal.open()
|
||||||
break
|
break
|
||||||
case 403:
|
case 403:
|
||||||
|
|
|
@ -1,34 +1,64 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { useCookies } from '@vueuse/integrations/useCookies'
|
||||||
|
import type { CookieChangeOptions } from 'universal-cookie'
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', {
|
export const useUserStore = defineStore('user', () => {
|
||||||
state: () => ({
|
const cookies = useCookies(['nginx-ui'])
|
||||||
token: '',
|
|
||||||
unreadCount: 0,
|
const token = ref('')
|
||||||
secureSessionId: '',
|
|
||||||
passkeyRawId: '',
|
watch(token, v => {
|
||||||
}),
|
cookies.set('token', v, { maxAge: 86400 })
|
||||||
getters: {
|
})
|
||||||
isLogin(state): boolean {
|
|
||||||
return !!state.token
|
const secureSessionId = ref('')
|
||||||
},
|
|
||||||
passkeyLoginAvailable(state): boolean {
|
watch(secureSessionId, v => {
|
||||||
return !!state.passkeyRawId
|
cookies.set('secure_session_id', v, { maxAge: 60 * 3 })
|
||||||
},
|
})
|
||||||
},
|
|
||||||
actions: {
|
function handleCookieChange({ name, value }: CookieChangeOptions) {
|
||||||
passkeyLogin(rawId: string, token: string) {
|
if (name === 'token')
|
||||||
this.passkeyRawId = rawId
|
token.value = value
|
||||||
this.login(token)
|
else if (name === 'secure_session_id')
|
||||||
},
|
secureSessionId.value = value
|
||||||
login(token: string) {
|
}
|
||||||
this.token = token
|
|
||||||
},
|
cookies.addChangeListener(handleCookieChange)
|
||||||
logout() {
|
|
||||||
this.token = ''
|
const passkeyRawId = ref('')
|
||||||
this.passkeyRawId = ''
|
|
||||||
this.secureSessionId = ''
|
const unreadCount = ref(0)
|
||||||
this.unreadCount = 0
|
const isLogin = computed(() => !!token.value)
|
||||||
},
|
const passkeyLoginAvailable = computed(() => !!passkeyRawId.value)
|
||||||
},
|
|
||||||
|
function passkeyLogin(rawId: string, tokenValue: string) {
|
||||||
|
passkeyRawId.value = rawId
|
||||||
|
login(tokenValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
function login(tokenValue: string) {
|
||||||
|
token.value = tokenValue
|
||||||
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
token.value = ''
|
||||||
|
passkeyRawId.value = ''
|
||||||
|
secureSessionId.value = ''
|
||||||
|
unreadCount.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
token,
|
||||||
|
unreadCount,
|
||||||
|
secureSessionId,
|
||||||
|
passkeyRawId,
|
||||||
|
isLogin,
|
||||||
|
passkeyLoginAvailable,
|
||||||
|
passkeyLogin,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
persist: true,
|
persist: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { KeyOutlined, LockOutlined, UserOutlined } from '@ant-design/icons-vue'
|
import { KeyOutlined, LockOutlined, UserOutlined } from '@ant-design/icons-vue'
|
||||||
import { Form, message } from 'ant-design-vue'
|
import { Form, message } from 'ant-design-vue'
|
||||||
import { useCookies } from '@vueuse/integrations/useCookies'
|
|
||||||
import { startAuthentication } from '@simplewebauthn/browser'
|
import { startAuthentication } from '@simplewebauthn/browser'
|
||||||
import { useUserStore } from '@/pinia'
|
import { useUserStore } from '@/pinia'
|
||||||
import auth from '@/api/auth'
|
import auth from '@/api/auth'
|
||||||
|
@ -60,13 +59,12 @@ const onSubmit = () => {
|
||||||
|
|
||||||
await auth.login(modelRef.username, modelRef.password, passcode.value, recoveryCode.value).then(async r => {
|
await auth.login(modelRef.username, modelRef.password, passcode.value, recoveryCode.value).then(async r => {
|
||||||
const next = (route.query?.next || '').toString() || '/'
|
const next = (route.query?.next || '').toString() || '/'
|
||||||
const cookies = useCookies(['nginx-ui-2fa'])
|
|
||||||
switch (r.code) {
|
switch (r.code) {
|
||||||
case 200:
|
case 200:
|
||||||
message.success($gettext('Login successful'), 1)
|
message.success($gettext('Login successful'), 1)
|
||||||
login(r.token)
|
login(r.token)
|
||||||
|
await nextTick()
|
||||||
secureSessionId.value = r.secure_session_id
|
secureSessionId.value = r.secure_session_id
|
||||||
cookies.set('secure_session_id', r.secure_session_id, { maxAge: 60 * 3 })
|
|
||||||
await router.push(next)
|
await router.push(next)
|
||||||
break
|
break
|
||||||
case 199:
|
case 199:
|
||||||
|
@ -159,7 +157,7 @@ async function handlePasskeyLogin() {
|
||||||
passkeyLoginLoading.value = true
|
passkeyLoginLoading.value = true
|
||||||
try {
|
try {
|
||||||
const begin = await auth.begin_passkey_login()
|
const begin = await auth.begin_passkey_login()
|
||||||
const asseResp = await startAuthentication(begin.options.publicKey)
|
const asseResp = await startAuthentication({ optionsJSON: begin.options.publicKey })
|
||||||
|
|
||||||
const r = await auth.finish_passkey_login({
|
const r = await auth.finish_passkey_login({
|
||||||
session_id: begin.session_id,
|
session_id: begin.session_id,
|
||||||
|
@ -167,13 +165,10 @@ async function handlePasskeyLogin() {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (r.token) {
|
if (r.token) {
|
||||||
const cookies = useCookies(['nginx-ui-2fa'])
|
|
||||||
const next = (route.query?.next || '').toString() || '/'
|
const next = (route.query?.next || '').toString() || '/'
|
||||||
|
|
||||||
passkeyLogin(asseResp.rawId, r.token)
|
passkeyLogin(asseResp.rawId, r.token)
|
||||||
secureSessionId.value = r.secure_session_id
|
secureSessionId.value = r.secure_session_id
|
||||||
cookies.set('secure_session_id', r.secure_session_id, { maxAge: 60 * 3 })
|
|
||||||
|
|
||||||
await router.push(next)
|
await router.push(next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue