Move session management into session store
Trying to get rid of the redirect to signin on any page refresh
This commit is contained in:
parent
bf156eaf7f
commit
efa01cffc2
8 changed files with 34 additions and 69 deletions
|
|
@ -13,12 +13,11 @@ onMounted(() => {
|
|||
session
|
||||
.get()
|
||||
.then((session: Session) => {
|
||||
console.log("session loaded", session);
|
||||
console.log("session loaded by AppSync", session);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("root session not loaded", e);
|
||||
router.push("/signin");
|
||||
});
|
||||
console.log("home mounted");
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import router from "@/router";
|
|||
|
||||
class ApiClient {
|
||||
private client: AxiosInstance;
|
||||
private _hasSession: boolean = false;
|
||||
private _isAuthenticated: boolean = false;
|
||||
|
||||
constructor() {
|
||||
|
|
@ -40,14 +41,6 @@ class ApiClient {
|
|||
);
|
||||
}
|
||||
|
||||
get isAuthenticated(): boolean {
|
||||
return this._isAuthenticated;
|
||||
}
|
||||
|
||||
setAuthenticated(value: boolean): void {
|
||||
this._isAuthenticated = value;
|
||||
}
|
||||
|
||||
async JSONGet<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||||
const response = await this.client.get<T>(url, {
|
||||
...config,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
<template>
|
||||
<div id="content">
|
||||
<div v-if="session.loading">Loading...</div>
|
||||
<div v-else-if="session.error">Error: {{ session.error }}</div>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSessionStore } from "@/store/session";
|
||||
|
||||
const session = useSessionStore();
|
||||
</script>
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
|||
51
ts/router.ts
51
ts/router.ts
|
|
@ -1,5 +1,7 @@
|
|||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import type { RouteRecordRaw } from "vue-router";
|
||||
|
||||
import { useSessionStore } from "@/store/session";
|
||||
import Home from "@/view/Home.vue";
|
||||
import Authenticated from "@/view/Authenticated.vue";
|
||||
import Communication from "@/view/Communication.vue";
|
||||
|
|
@ -43,53 +45,44 @@ const routes: RouteRecordRaw[] = [
|
|||
path: "/_/communication",
|
||||
name: "Communication",
|
||||
component: Communication,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration",
|
||||
name: "Configuration",
|
||||
component: ConfigurationRoot,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/integration",
|
||||
name: "Integration Configuration",
|
||||
component: ConfigurationIntegration,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/integration/arcgis",
|
||||
name: "Arcgis Integration Configuration",
|
||||
component: ConfigurationIntegrationArcgis,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/organization",
|
||||
name: "Organization Configuration",
|
||||
component: ConfigurationOrganization,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/pesticide",
|
||||
name: "Pesticide Configuration",
|
||||
component: ConfigurationPesticide,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/pesticide/add",
|
||||
name: "Pesticide Add",
|
||||
component: ConfigurationPesticideAdd,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/upload",
|
||||
name: "Upload Configuration",
|
||||
component: ConfigurationUpload,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
component: ConfigurationUploadDetail,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
name: "Upload Detail",
|
||||
path: "/_/configuration/upload/:id",
|
||||
props: (route) => ({
|
||||
|
|
@ -100,35 +93,29 @@ const routes: RouteRecordRaw[] = [
|
|||
path: "/_/configuration/upload/pool",
|
||||
name: "Pool Upload",
|
||||
component: ConfigurationUploadPool,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/upload/pool/custom",
|
||||
name: "Custom Pool Upload",
|
||||
component: ConfigurationUploadPoolCustom,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/upload/pool/flyover",
|
||||
name: "Flyover Upload",
|
||||
component: ConfigurationUploadPoolFlyover,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/user",
|
||||
name: "User Configuration",
|
||||
component: ConfigurationUser,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/configuration/user/add",
|
||||
name: "User Add Configuration",
|
||||
component: ConfigurationUserAdd,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
component: ConfigurationUserEdit,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
name: "User Edit",
|
||||
path: "/_/configuration/user/:id",
|
||||
props: (route) => ({
|
||||
|
|
@ -144,49 +131,41 @@ const routes: RouteRecordRaw[] = [
|
|||
path: "/_/intelligence",
|
||||
name: "Intelligence",
|
||||
component: Intelligence,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/oauth/refresh/arcgis",
|
||||
name: "Arcgis OAuth Refresh",
|
||||
component: OAuthRefreshArcgis,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/operations",
|
||||
name: "Operations",
|
||||
component: Operations,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/planning",
|
||||
name: "Planning",
|
||||
component: Planning,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/review",
|
||||
name: "Review",
|
||||
component: ReviewRoot,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/review/pool",
|
||||
name: "Pool Review",
|
||||
component: ReviewPool,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/review/site",
|
||||
name: "Site Review",
|
||||
component: ReviewSite,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
{
|
||||
path: "/_/sudo",
|
||||
name: "Sudo",
|
||||
component: Sudo,
|
||||
meta: { requiresAuth: true, showSidebar: true },
|
||||
},
|
||||
],
|
||||
component: Authenticated,
|
||||
|
|
@ -218,21 +197,19 @@ export const router = createRouter({
|
|||
|
||||
// Global navigation guard
|
||||
router.beforeEach(async (to, from) => {
|
||||
const requiresAuth = to.matched.some((record) => record.meta.requiresAuth);
|
||||
|
||||
if (requiresAuth) {
|
||||
try {
|
||||
// Check if user is authenticated (could be an API call)
|
||||
if (!apiClient.isAuthenticated) {
|
||||
return "/signin";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("check auth failed");
|
||||
return "/signin";
|
||||
}
|
||||
if (to.fullPath == "/signin") {
|
||||
return;
|
||||
}
|
||||
const storeSession = useSessionStore();
|
||||
try {
|
||||
if (!storeSession.isLoading && !storeSession.isAuthenticated) {
|
||||
console.log("sending to signin because we're not authenticated");
|
||||
return `/signin?next=${from.fullPath}`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("check auth failed");
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -12,9 +12,11 @@ import { apiClient } from "@/client";
|
|||
|
||||
export const useSessionStore = defineStore("session", () => {
|
||||
// State
|
||||
const hasSession = ref<boolean>(false);
|
||||
const isAuthenticated = ref<boolean>(false);
|
||||
const isLoading = ref(true);
|
||||
const impersonating = ref<string | null>(null);
|
||||
const error = ref<string | null>(null);
|
||||
const loading = ref(true);
|
||||
const current = ref<Session | null>(null);
|
||||
const notification_counts = ref<SessionNotificationCounts | null>(null);
|
||||
const ongoingFetch = ref<Promise<Session> | null>(null);
|
||||
|
|
@ -31,12 +33,11 @@ export const useSessionStore = defineStore("session", () => {
|
|||
|
||||
// Actions
|
||||
async function fetchSession(): Promise<Session> {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const data: Session = await apiClient.JSONGet("/api/session");
|
||||
apiClient.setAuthenticated(true);
|
||||
isAuthenticated.value = true;
|
||||
impersonating.value = data.impersonating || null;
|
||||
notification_counts.value = data.notification_counts;
|
||||
organization.value = data.organization;
|
||||
|
|
@ -44,19 +45,19 @@ export const useSessionStore = defineStore("session", () => {
|
|||
urls.value = data.urls;
|
||||
return data;
|
||||
} catch (e) {
|
||||
apiClient.setAuthenticated(false);
|
||||
error.value = e instanceof Error ? e.message : "an error ocurred";
|
||||
console.error("Error fetching user:", e);
|
||||
throw new Error(error.value);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
hasSession.value = true;
|
||||
isLoading.value = false;
|
||||
console.log("no longer loading session");
|
||||
}
|
||||
}
|
||||
|
||||
async function isAuthenticated(): Promise<boolean> {
|
||||
console.log("pretend check user auth");
|
||||
return true;
|
||||
async function getAuthenticated(): Promise<boolean> {
|
||||
await get();
|
||||
return isAuthenticated.value;
|
||||
}
|
||||
|
||||
async function get(): Promise<Session> {
|
||||
|
|
@ -74,13 +75,17 @@ export const useSessionStore = defineStore("session", () => {
|
|||
return s;
|
||||
}
|
||||
async function signout(): Promise<void> {
|
||||
isAuthenticated.value = false;
|
||||
apiClient.JSONPost("/api/signout", {});
|
||||
}
|
||||
return {
|
||||
// State
|
||||
error,
|
||||
getAuthenticated,
|
||||
hasSession,
|
||||
impersonating,
|
||||
loading,
|
||||
isAuthenticated,
|
||||
isLoading,
|
||||
notification_counts,
|
||||
organization,
|
||||
self,
|
||||
|
|
@ -88,7 +93,6 @@ export const useSessionStore = defineStore("session", () => {
|
|||
// Actions
|
||||
fetchSession,
|
||||
get,
|
||||
isAuthenticated,
|
||||
signout,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
</style>
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<template v-if="session.loading">Loading...</template>
|
||||
<template v-if="session.isLoading">Loading...</template>
|
||||
<template v-else-if="session.error">Error: {{ session.error }}</template>
|
||||
<template v-else>
|
||||
<Sidebar />
|
||||
|
|
|
|||
|
|
@ -12,13 +12,12 @@ onMounted(() => {
|
|||
session
|
||||
.get()
|
||||
.then((session: Session) => {
|
||||
console.log("session loaded", session);
|
||||
console.log("hit home with a valid session, going to dash");
|
||||
router.push("/_/dash");
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("root session not loaded", e);
|
||||
console.log("hit home with no session, going to signin");
|
||||
router.push("/signin");
|
||||
});
|
||||
console.log("home mounted");
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { useSessionStore } from "@/store/session";
|
|||
const session = useSessionStore();
|
||||
onMounted(() => {
|
||||
session.signout().then(() => {
|
||||
apiClient.setAuthenticated(false);
|
||||
router.push("/signin");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue