diff --git a/components/UserMenu.vue b/components/UserMenu.vue index 7cc671d..2c6b65b 100755 --- a/components/UserMenu.vue +++ b/components/UserMenu.vue @@ -23,7 +23,7 @@ diff --git a/components/auth/CallbackHint.vue b/components/auth/CallbackHint.vue index 1eb5896..a25a283 100644 --- a/components/auth/CallbackHint.vue +++ b/components/auth/CallbackHint.vue @@ -2,7 +2,7 @@
- You need to sign in before access that page. After you signed in, we will redirect you to:
+ {{ t("callbackHint") }}
{{ route.query["redirect_uri"] }}
@@ -10,5 +10,6 @@ diff --git a/lang/en-US.json b/lang/en-US.json index 92b24e0..731505a 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -40,5 +40,6 @@ "securityCaption": "Guard your Solar Network account.", "userActivity": "Activity", "userActivityCaption": "Recent posts of this user.", - "productArchived": "Archived" + "productArchived": "Archived", + "callbackHint": "You need to sign in before access that page. After you signed in, you will be redirected to:" } diff --git a/lang/zh-CN.json b/lang/zh-CN.json index 7dd4915..227aa29 100644 --- a/lang/zh-CN.json +++ b/lang/zh-CN.json @@ -40,5 +40,6 @@ "securityCaption": "保护您的 Solar Network 账户。", "userActivity": "活动", "userActivityCaption": "此用户的最新帖子。", - "productArchived": "已归档" + "productArchived": "已归档", + "callbackHint": "访问该页面前,您需要先登录。登录后,我们会将把您重定向到:" } diff --git a/middleware/auth.ts b/middleware/auth.ts index ad69709..b069705 100644 --- a/middleware/auth.ts +++ b/middleware/auth.ts @@ -1,7 +1,7 @@ export default defineNuxtRouteMiddleware((to, from) => { - const id = useUserinfo(); + const state = useLoggedInState() - if (!id.isLoggedIn) { + if (!state.value) { return navigateTo(`/auth/sign-in?redirect_uri=${to.fullPath}`) } }) diff --git a/pages/auth/sign-in.vue b/pages/auth/sign-in.vue index 5bc10f5..a4471e0 100644 --- a/pages/auth/sign-in.vue +++ b/pages/auth/sign-in.vue @@ -59,6 +59,21 @@ async function pickUpTicket() { onMounted(() => pickUpTicket()) +const id = useUserinfo() +const router = useRouter() + +watch(id, (value) => { + if (value.isLoggedIn) { + if (route.query["close"]) { + window.close() + } else if (route.query["redirect_uri"]) { + window.open((route.query["redirect_uri"] as string) ?? "/", "_self") + } else { + router.push("/users/me") + } + } +}, { deep: true, immediate: true }) + const panel = ref("authenticate") const panels: { [id: string]: Component } = { diff --git a/stores/userinfo.ts b/stores/userinfo.ts index 2bf8210..ae1a600 100644 --- a/stores/userinfo.ts +++ b/stores/userinfo.ts @@ -2,18 +2,6 @@ import { defineStore } from "pinia" import { ref } from "vue" import { solarFetch } from "~/utils/request" -export interface Userinfo { - isLoggedIn: boolean - displayName: string - data: any -} - -export const defaultUserinfo: Userinfo = { - isLoggedIn: false, - displayName: "Citizen", - data: null, -} - export function useAtk() { return useCookie("__hydrogen_atk", { watch: "shallow" }) } @@ -31,6 +19,9 @@ export const useUserinfo = defineStore("userinfo", () => { const isReady = ref(false) const isLoggedIn = ref(false) + let fetchCompleter: Completer | null = null + let refreshCompleter: Completer | null = null + const lastRefreshedAt = ref(null) function setTokenSet(atk: string, rtk: string) { @@ -45,6 +36,12 @@ export const useUserinfo = defineStore("userinfo", () => { return useAtk().value } + if (refreshCompleter != null) { + return await refreshCompleter.promise + } else { + refreshCompleter = new Completer() + } + const config = useRuntimeConfig() const res = await fetch(`${config.public.solarNetworkApi}/cgi/auth/auth/token`, { @@ -62,18 +59,28 @@ export const useUserinfo = defineStore("userinfo", () => { const out = await res.json() console.log("[PASSPORT] Access token has been refreshed now.") setTokenSet(out["access_token"], out["refresh_token"]) + refreshCompleter.complete(out["access_token"]) return out["access_token"] } } async function readProfiles() { + if (fetchCompleter != null) { + await fetchCompleter.promise + return + } else { + fetchCompleter = new Completer() + } + if (!useLoggedInState().value) { + fetchCompleter.complete(true) isReady.value = true } const res = await solarFetch("/cgi/auth/users/me") if (res.status !== 200) { + fetchCompleter.complete(true) isReady.value = true return } @@ -83,7 +90,21 @@ export const useUserinfo = defineStore("userinfo", () => { isLoggedIn.value = true isReady.value = true userinfo.value = data + fetchCompleter.complete(true) } - return { userinfo, lastRefreshedAt, isLoggedIn, isReady, setTokenSet, getAtk, readProfiles } + return { userinfo, lastRefreshedAt, isLoggedIn, isReady, fetchCompleter, setTokenSet, getAtk, readProfiles } }) + +export class Completer { + public readonly promise: Promise + public complete: (value: (PromiseLike | T)) => void + private reject: (reason?: any) => void + + public constructor() { + this.promise = new Promise((resolve, reject) => { + this.complete = resolve + this.reject = reject + }) + } +} diff --git a/tsconfig.json b/tsconfig.json index a746f2a..3a7b85c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,7 @@ { // https://nuxt.com/docs/guide/concepts/typescript - "extends": "./.nuxt/tsconfig.json" + "extends": "./.nuxt/tsconfig.json", + "compilerOptions": { + "strictPropertyInitialization": false + } }