From 97215324232c0ebdd024b498bc90eed680807398 Mon Sep 17 00:00:00 2001 From: Florian Sylvain Date: Thu, 12 Jan 2023 11:09:12 +0100 Subject: [PATCH] Final httpOnly JWT token implementation front+back --- cmd/main.go | 1 + web/admin-gui/src/components/Navbar.vue | 11 ++++- web/admin-gui/src/router/index.ts | 15 ++----- web/admin-gui/src/stores/AuthStore.ts | 21 +++------ web/admin-gui/src/utils/api.ts | 1 + web/admin-gui/src/utils/database.ts | 7 ++- web/admin-gui/src/views/Debug.vue | 59 ------------------------- web/admin-gui/src/views/Login.vue | 13 ++---- 8 files changed, 26 insertions(+), 102 deletions(-) create mode 100644 web/admin-gui/src/utils/api.ts delete mode 100644 web/admin-gui/src/views/Debug.vue diff --git a/cmd/main.go b/cmd/main.go index ee26f6c..15409ba 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -37,6 +37,7 @@ func initJWT() { func initBasicRoutes(r *gin.Engine) { r.POST("/login/", api.AuthMiddleware.LoginHandler) + r.POST("/logout/", api.AuthMiddleware.LogoutHandler) r.GET("/ping/", api.Ping) } diff --git a/web/admin-gui/src/components/Navbar.vue b/web/admin-gui/src/components/Navbar.vue index 2a353f0..8bc7072 100644 --- a/web/admin-gui/src/components/Navbar.vue +++ b/web/admin-gui/src/components/Navbar.vue @@ -2,13 +2,20 @@ import { useAuthStore } from '@/stores/AuthStore'; import { deleteCookie } from '@/utils/cookies'; import { RouterLink, useRouter } from 'vue-router' +import { baseApiUrl } from "@/utils/api" const router = useRouter() function logout() { - deleteCookie('JWTtoken') - deleteCookie('JWTexpire') + deleteCookie('jwt_expire') useAuthStore().clearAll() + + fetch(`${baseApiUrl}/logout`, { + method: 'POST', + credentials: 'include' + }) + .catch(error => console.error(error)) + router.push('/') } diff --git a/web/admin-gui/src/router/index.ts b/web/admin-gui/src/router/index.ts index e6b7a88..3c5d77a 100644 --- a/web/admin-gui/src/router/index.ts +++ b/web/admin-gui/src/router/index.ts @@ -1,7 +1,6 @@ import { createRouter, createWebHistory } from 'vue-router' import { useAuthStore } from '@/stores/AuthStore' import { nextTick } from 'vue' -import Debug from '@/views/Debug.vue' import Login from '@/views/Login.vue' import Home from '@/views/Home.vue' import Articles from '@/views/Articles.vue' @@ -19,14 +18,6 @@ const router = createRouter({ title: 'GohCMS - Connexion' } }, - { - path: '/debug', - name: 'debug', - component: Debug, - meta: { - title: 'GohCMS - Debug' - } - }, { path: '/home', name: 'home', @@ -63,13 +54,13 @@ const router = createRouter({ }) router.beforeEach(async (to, from) => { - const isTokenValid = useAuthStore().isValid() + const isJwtExpired = useAuthStore().isExpired() if (to.name === 'login') { - if (isTokenValid) return { + if (!isJwtExpired) return { name: 'home' } } else { - if (!isTokenValid) { + if (isJwtExpired) { return { name: 'login', } diff --git a/web/admin-gui/src/stores/AuthStore.ts b/web/admin-gui/src/stores/AuthStore.ts index 7bcab6f..0c3f847 100644 --- a/web/admin-gui/src/stores/AuthStore.ts +++ b/web/admin-gui/src/stores/AuthStore.ts @@ -6,23 +6,18 @@ import { useErrorsStore } from "./ErrorsStore"; export interface jwtFormat { code: number, expire: string, - token: string + message: string } export const useAuthStore = defineStore("AuthStore", () => { const expire = ref('') - const token = ref('') function clearAll(): void { expire.value = '' - token.value = '' } - function isSet(): boolean { - return token.value !== undefined && token.value !== '' - } - function isExpired(): boolean { + if (expire.value === '') return true; const tokenDate = new Date(expire.value) const currentDate = new Date() @@ -33,20 +28,14 @@ export const useAuthStore = defineStore("AuthStore", () => { return false } - function isValid(): boolean { - return isSet() && !isExpired() - } - function initStore(): void { - const JWTtoken = getCookie('JWTtoken') - const JWTexpire = getCookie('JWTexpire') - if (JWTtoken !== "" && JWTexpire !== "") { - token.value = JWTtoken + const JWTexpire = getCookie('jwt_expire') + if (JWTexpire !== "") { expire.value = JWTexpire } } initStore() - return { expire, token, isValid, clearAll } + return { expire, clearAll, isExpired} }) \ No newline at end of file diff --git a/web/admin-gui/src/utils/api.ts b/web/admin-gui/src/utils/api.ts new file mode 100644 index 0000000..811326d --- /dev/null +++ b/web/admin-gui/src/utils/api.ts @@ -0,0 +1 @@ +export const baseApiUrl = `http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}` \ No newline at end of file diff --git a/web/admin-gui/src/utils/database.ts b/web/admin-gui/src/utils/database.ts index 1d91e2f..5d8f9da 100644 --- a/web/admin-gui/src/utils/database.ts +++ b/web/admin-gui/src/utils/database.ts @@ -1,4 +1,5 @@ import { useAuthStore } from "@/stores/AuthStore" +import { baseApiUrl } from "@/utils/api" export interface Article { titleID: string, @@ -11,10 +12,8 @@ export interface Article { online: boolean } -const baseURL = `http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}` - export async function getArticles(id: string) : Promise> { - return await fetch(`${baseURL}/articles/${id}`, { + return await fetch(`${baseApiUrl}/articles/${id}`, { credentials: 'include', method: 'GET', }) @@ -25,7 +24,7 @@ export async function getArticles(id: string) : Promise> { } export async function postArticle(article: Article) : Promise { - return await fetch(`${baseURL}/articles/${article.titleID}`, { + return await fetch(`${baseApiUrl}/articles/${article.titleID}`, { credentials: 'include', method: 'POST', body: JSON.stringify(article) diff --git a/web/admin-gui/src/views/Debug.vue b/web/admin-gui/src/views/Debug.vue deleted file mode 100644 index 55faf2a..0000000 --- a/web/admin-gui/src/views/Debug.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/admin-gui/src/views/Login.vue b/web/admin-gui/src/views/Login.vue index 5dc2cf6..a7485ca 100644 --- a/web/admin-gui/src/views/Login.vue +++ b/web/admin-gui/src/views/Login.vue @@ -1,6 +1,7 @@