refactor: session handling (#2398)

* refactor session handling

* simplify
This commit is contained in:
Bernd Storath
2026-01-13 10:11:13 +01:00
committed by GitHub
parent b85286f0ab
commit 51558c7027
11 changed files with 38 additions and 31 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
"aaron-bond.better-comments", "aaron-bond.better-comments",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"antfu.goto-alias", "antfu.goto-alias",
"esbenp.prettier-vscode", "prettier.prettier-vscode",
"yoavbls.pretty-ts-errors", "yoavbls.pretty-ts-errors",
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
"vue.volar", "vue.volar",
+5 -5
View File
@@ -1,22 +1,22 @@
{ {
"editor.tabSize": 2, "editor.tabSize": 2,
"editor.useTabStops": false, "editor.useTabStops": false,
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "prettier.prettier-vscode",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": "always" "source.fixAll.eslint": "always"
}, },
"[vue]": { "[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "prettier.prettier-vscode"
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "prettier.prettier-vscode"
}, },
"[json]": { "[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "prettier.prettier-vscode"
}, },
"[markdown]": { "[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "prettier.prettier-vscode",
"editor.tabSize": 4, "editor.tabSize": 4,
"editor.useTabStops": false "editor.useTabStops": false
}, },
+6 -4
View File
@@ -4,25 +4,27 @@ export default defineNuxtRouteMiddleware(async (to) => {
return; return;
} }
const event = useRequestEvent();
const authStore = useAuthStore(); const authStore = useAuthStore();
const userData = await authStore.getSession(); authStore.userData = await authStore.getSession(event);
// skip login if already logged in // skip login if already logged in
if (to.path === '/login') { if (to.path === '/login') {
if (userData?.username) { if (authStore.userData?.username) {
return navigateTo('/', { redirectCode: 302 }); return navigateTo('/', { redirectCode: 302 });
} }
return; return;
} }
// Require auth for every page other than Login // Require auth for every page other than Login
if (!userData?.username) { if (!authStore.userData?.username) {
return navigateTo('/login', { redirectCode: 302 }); return navigateTo('/login', { redirectCode: 302 });
} }
// Check for admin access // Check for admin access
if (to.path.startsWith('/admin')) { if (to.path.startsWith('/admin')) {
if (!hasPermissions(userData, 'admin', 'any')) { if (!hasPermissions(authStore.userData, 'admin', 'any')) {
return abortNavigation('Not allowed to access Admin Panel'); return abortNavigation('Not allowed to access Admin Panel');
} }
} }
-3
View File
@@ -38,9 +38,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const authStore = useAuthStore();
authStore.update();
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
-2
View File
@@ -206,9 +206,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
const authStore = useAuthStore();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
authStore.update();
const route = useRoute(); const route = useRoute();
const id = route.params.id as string; const id = route.params.id as string;
-3
View File
@@ -29,9 +29,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const authStore = useAuthStore();
authStore.update();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const clientsStore = useClientsStore(); const clientsStore = useClientsStore();
-3
View File
@@ -67,9 +67,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const authStore = useAuthStore();
authStore.update();
const toast = useToast(); const toast = useToast();
const { t } = useI18n(); const { t } = useI18n();
-1
View File
@@ -120,7 +120,6 @@
import { encodeQR } from 'qr'; import { encodeQR } from 'qr';
const authStore = useAuthStore(); const authStore = useAuthStore();
authStore.update();
const name = ref(authStore.userData?.name); const name = ref(authStore.userData?.name);
const email = ref(authStore.userData?.email); const email = ref(authStore.userData?.email);
+14 -7
View File
@@ -1,18 +1,25 @@
export const useAuthStore = defineStore('Auth', () => { import type { H3Event } from 'h3';
const { data: userData, refresh: update } = useFetch('/api/session', { import type { SharedPublicUser } from '~~/shared/utils/permissions';
method: 'get',
});
async function getSession() { export const useAuthStore = defineStore('Auth', () => {
const userData = useState<SharedPublicUser | null>('user-data', () => null);
async function getSession(event?: H3Event) {
const fetch = event?.$fetch || $fetch;
try { try {
const { data } = await useFetch('/api/session', { const data = await fetch('/api/session', {
method: 'get', method: 'get',
}); });
return data.value; return data;
} catch { } catch {
return null; return null;
} }
} }
async function update() {
const data = await getSession();
userData.value = data;
}
return { userData, update, getSession }; return { userData, update, getSession };
}); });
+7 -2
View File
@@ -1,9 +1,14 @@
import type { SharedPublicUser } from '~~/shared/utils/permissions';
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
const session = await useWGSession(event); const session = await useWGSession(event);
if (!session.data.userId) { if (!session.data.userId) {
// not logged in // not logged in
return null; throw createError({
statusCode: 401,
statusMessage: 'Not authenticated',
});
} }
const user = await Database.users.get(session.data.userId); const user = await Database.users.get(session.data.userId);
@@ -21,5 +26,5 @@ export default defineEventHandler(async (event) => {
name: user.name, name: user.name,
email: user.email, email: user.email,
totpVerified: user.totpVerified, totpVerified: user.totpVerified,
}; } satisfies SharedPublicUser;
}); });
+5
View File
@@ -45,6 +45,11 @@ type SharedUserType =
| Pick<UserType, 'id' | 'role'> | Pick<UserType, 'id' | 'role'>
| (Pick<UserType, 'id'> & { role: BrandedNumber }); | (Pick<UserType, 'id'> & { role: BrandedNumber });
export type SharedPublicUser = Pick<
UserType,
'id' | 'username' | 'name' | 'email' | 'totpVerified'
> & { role: BrandedNumber };
type PermissionCheck<Key extends keyof Permissions> = type PermissionCheck<Key extends keyof Permissions> =
| boolean | boolean
| ((user: SharedUserType, data: Permissions[Key]['dataType']) => boolean); | ((user: SharedUserType, data: Permissions[Key]['dataType']) => boolean);