♻️ Refactored the auth flow

This commit is contained in:
2025-10-01 22:52:23 +08:00
parent 3e68158b4e
commit 6853acea98
4 changed files with 23 additions and 63 deletions

View File

@@ -11,28 +11,6 @@ export const useSolarNetwork = (withoutProxy = false) => {
onRequest: ({ request, options }) => { onRequest: ({ request, options }) => {
const side = process.server ? "SERVER" : "CLIENT" const side = process.server ? "SERVER" : "CLIENT"
console.log(`[useSolarNetwork] onRequest for ${request} on ${side}`) console.log(`[useSolarNetwork] onRequest for ${request} on ${side}`)
// Get token from user store
const userStore = useUserStore()
const token = userStore.token
if (token) {
console.log(
"[useSolarNetwork] Token found, adding Authorization header."
)
if (!options.headers) {
options.headers = new Headers()
}
if (options.headers instanceof Headers) {
options.headers.set("Authorization", `Bearer ${token}`)
} else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(options.headers as any)["Authorization"] = `Bearer ${token}`
}
} else {
console.log(
"[useSolarNetwork] No token found, skipping Authorization header."
)
}
// Transform request data from camelCase to snake_case // Transform request data from camelCase to snake_case
if (options.body && typeof options.body === "object") { if (options.body && typeof options.body === "object") {

View File

@@ -201,7 +201,8 @@ async function exchangeToken() {
isLoading.value = true isLoading.value = true
error.value = null error.value = null
try { try {
const tokenResponse = await api<{ token: string }>("/id/auth/token", { // The token endpoint gives the Set-Cookie header
await api<{ token: string }>("/id/auth/token", {
method: "POST", method: "POST",
body: { body: {
grant_type: "authorization_code", grant_type: "authorization_code",
@@ -209,11 +210,6 @@ async function exchangeToken() {
} }
}) })
// Store the token in localStorage via user store
if (tokenResponse && tokenResponse.token) {
userStore.setToken(tokenResponse.token)
}
await userStore.fetchUser() await userStore.fetchUser()
const redirectUri = route.query.redirect_uri as string const redirectUri = route.query.redirect_uri as string
@@ -374,14 +370,14 @@ const colorMode = useColorMode()
factor.type === 0 factor.type === 0
? "mdi-lock" ? "mdi-lock"
: factor.type === 1 : factor.type === 1
? "mdi-email" ? "mdi-email"
: factor.type === 2 : factor.type === 2
? "mdi-cellphone" ? "mdi-cellphone"
: factor.type === 3 : factor.type === 3
? "mdi-clock" ? "mdi-clock"
: factor.type === 4 : factor.type === 4
? "mdi-numeric" ? "mdi-numeric"
: "mdi-shield-key" : "mdi-shield-key"
}}</v-icon> }}</v-icon>
</template> </template>
</v-list-item> </v-list-item>

View File

@@ -1,24 +1,24 @@
import { useUserStore } from '~/stores/user' import { useUserStore } from "~/stores/user"
export default defineNuxtPlugin(() => { export default defineNuxtPlugin(() => {
const side = process.server ? 'SERVER' : 'CLIENT' const side = process.server ? "SERVER" : "CLIENT"
console.log(`[AUTH PLUGIN] Running on ${side}`) console.log(`[AUTH PLUGIN] Running on ${side}`)
const userStore = useUserStore() const userStore = useUserStore()
// Prevent fetching if it's already in progress // Prevent fetching if it's already in progress
if (userStore.isLoading) { if (userStore.isLoading) {
console.log(`[AUTH PLUGIN] User fetch already in progress on ${side}. Skipping.`) console.log(
`[AUTH PLUGIN] User fetch already in progress on ${side}. Skipping.`
)
return return
} }
// On initial app load, fetch the user if a token exists but the user object isn't populated. // On initial app load, fetch the user if a token exists but the user object isn't populated.
if (userStore.token && !userStore.user) { if (!userStore.user) {
console.log(`[AUTH PLUGIN] Token found, user not loaded. Fetching user on ${side}.`) console.log(
`[AUTH PLUGIN] User not loaded. Trying to fetching user on ${side}.`
)
userStore.fetchUser() userStore.fetchUser()
} else {
console.log(`[AUTH PLUGIN] Conditions not met for fetching user on ${side}.`, {
hasToken: !!userStore.token,
hasUser: !!userStore.user
})
} }
}) })

View File

@@ -10,15 +10,8 @@ export const useUserStore = defineStore("user", () => {
const isLoading = ref(false) const isLoading = ref(false)
const error = ref<string | null>(null) const error = ref<string | null>(null)
// The name is match with the remote one (set by server Set-Cookie)
const token = useCookie<string | null>("fl_AuthToken", {
default: () => null,
path: "/",
maxAge: 60 * 60 * 24 * 365 * 10
}) // 10 years
// Getters // Getters
const isAuthenticated = computed(() => !!user.value && !!token.value) const isAuthenticated = computed(() => !!user.value)
// Actions // Actions
async function fetchUser(reload = true) { async function fetchUser(reload = true) {
@@ -32,7 +25,7 @@ export const useUserStore = defineStore("user", () => {
const response = await api("/id/accounts/me") const response = await api("/id/accounts/me")
user.value = response as SnAccount user.value = response as SnAccount
console.log(`Logged in as ${user.value.name}`) console.log(`[UserStore] Logged in as ${user.value.name}`)
} catch (e: unknown) { } catch (e: unknown) {
if (e instanceof FetchError && e.statusCode == 401) { if (e instanceof FetchError && e.statusCode == 401) {
error.value = "Unauthorized" error.value = "Unauthorized"
@@ -47,23 +40,16 @@ export const useUserStore = defineStore("user", () => {
} }
} }
function setToken(newToken: string) {
token.value = newToken
}
function logout() { function logout() {
user.value = null user.value = null
token.value = null
} }
return { return {
user, user,
token,
isLoading, isLoading,
error, error,
isAuthenticated, isAuthenticated,
fetchUser, fetchUser,
setToken,
logout logout
} }
}) })