From b5a169282b591700d8f82d294e3e7ff5f73a268c Mon Sep 17 00:00:00 2001 From: Markus Thielen Date: Thu, 9 Mar 2023 11:19:53 +0100 Subject: [PATCH] login, logout, store, ... --- src/App.vue | 7 +++-- src/components/OAuthCallback.vue | 27 ---------------- src/router/index.js | 54 +++++++++----------------------- src/store.js | 22 +++++++++++-- src/util/net.js | 23 ++++++-------- src/util/oauth.js | 47 +++++++++++---------------- src/views/HomeView.vue | 5 +-- 7 files changed, 70 insertions(+), 115 deletions(-) delete mode 100644 src/components/OAuthCallback.vue diff --git a/src/App.vue b/src/App.vue index 60a16a3..4e0f5da 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,12 +2,13 @@ import { RouterLink, RouterView } from 'vue-router' import HelloWorld from './components/Welcome.vue' import { store } from './store.js' - +import {clearSession} from "./store.js"; /** * Logout the user. */ function logOut() { - store.loggedIn = false; + clearSession(); + location.href = "/"; } @@ -22,7 +23,7 @@ function logOut() { diff --git a/src/components/OAuthCallback.vue b/src/components/OAuthCallback.vue deleted file mode 100644 index e86c662..0000000 --- a/src/components/OAuthCallback.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/src/router/index.js b/src/router/index.js index d0da141..2ea8559 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -10,6 +10,7 @@ import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' import OAUthError from "../components/OAUthError.vue"; import { objectToQueryString } from "../util/net"; +import {createUser, oauthCallbackHandler} from "../util/oauth"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -44,48 +45,23 @@ router.beforeEach(async (to, from) => { if (to.path === "/oauth-callback") { let queryString = objectToQueryString(to.query); console.info(`Got /oauth-callback with query string '${queryString}`); - /* Pass the query parameters to the broker to complete login. We will get - * the session token and user data in return. - * - * The URL we post to is broker's base URL and the `openid_connect_path` - * setting from broker's config. - */ - const response = await fetch(`${store.baseboxHost}/oauth/complete-login?${queryString}`, { - method: "POST", - }); - if (!response.ok) { - /* redirect to error component */ - console.error("Failed to complete login/get session data: " + response.statusText); - return { - name: 'oauth-error', - query: { - code: response.status, - addlInfo: await response.text() - } - } + + /* Pass the query string to the handler function */ + try { + await oauthCallbackHandler(queryString); + /* Success; redirect to home */ + } catch (err) { + console.error("Failed to finish login: " + err); } - /* store session data; this is a JSON object of the following form: - { - "token":"47caa9df-ac89-45a8-8b22-9c0925d6aed0", - "username":"tester", - "first_name":"Fred", - "last_name":"Feuerstein", - "roles":[ - "/user" - ], - "claims":{ - "groups":[ - "/user" - ] - } - } - */ - store.session = await response.json(); - store.userName = store.session.first_name ? store.session.first_name : store.session.username; + /* We have to create the logged-in user explicitly; see comment for `createUser()` */ + try { + await createUser(); + } catch (err) { + console.error("Failed to create user: " + err); + } - /* redirect to home */ - return { name: 'home' }; + return {name: 'home'}; } }); diff --git a/src/store.js b/src/store.js index 7eec886..72953c4 100644 --- a/src/store.js +++ b/src/store.js @@ -11,11 +11,27 @@ export const store = reactive({ /** Username of the currently logged-in user */ userName: "stranger", - /** The host that runs basebox and waits for GraphQL requests */ + /** base URL of basebox broker host */ baseboxHost: "http://127.0.0.1:8080", /** basebox session data */ - session: null, + session: {}, + +}); + +/** + * Return true if the user is logged in. + */ +export function loggedIn() { + return store.session && store.session.token; +} + +/** + * Clear session data. + */ +export function clearSession() { + store.session = {}; +} + -}) diff --git a/src/util/net.js b/src/util/net.js index 934a10d..3a004f8 100644 --- a/src/util/net.js +++ b/src/util/net.js @@ -5,8 +5,7 @@ * https://basebox.tech */ -import {store} from "../store"; -import router from "../router"; +import {clearSession, store} from "../store"; /** * GqlError - custom error thrown by the gqlQuery function. @@ -114,7 +113,7 @@ export function gqlQuery(query) console.info(fetchOpt); - return fetch(store.getters.gqlUrl, fetchOpt).then( + return fetch(`${store.baseboxHost}/graphql`, fetchOpt).then( /* fetch success */ async response => { if (response.ok) { @@ -128,27 +127,25 @@ export function gqlQuery(query) } else { /* some errors... */ return new Promise((resolve, reject) => { - const error = new GqlError(rspJson); - /* if this is a 401, we redirect to the login page */ - if (error.is401()) { - router.push({ - name: "Login", - query: { - next: router.currentRoute.fullPath, - } - }); - } reject(new GqlError(rspJson)); }); } } else { /* low level/network error */ + /* if this is a 401, we clear the session data */ + if (response.status === 401) { + console.error("Last request failed: unauthorized. Clearing session."); + clearSession(); + return new Promise((resolve, reject) => reject("Unauthorized")); + } + return new Promise((resolve, reject) => { reject(new GqlError(response.statusText)); }); } }, + /* fetch failure */ reason => { return new Promise((resolve, reject) => { diff --git a/src/util/oauth.js b/src/util/oauth.js index 08d5214..2f31e22 100644 --- a/src/util/oauth.js +++ b/src/util/oauth.js @@ -44,23 +44,18 @@ import {gqlQuery} from "./net"; */ export async function oauthCallbackHandler(queryString) { - fetch(`${store.baseboxHost}/oauth/complete-login?${queryString}`, { + /* Pass query string to the broker to complete the login process. */ + const response = await fetch(`${store.baseboxHost}/oauth/complete-login?${queryString}`, { method: "POST", - }).then(response => { - if (!response.ok) { - throw new Error("Failed to get session data: " + response.statusText); - } - - /* Store session data */ - response.json( - ).then(rspJson => { - store.session = rspJson; - store.userName = store.session.first_name ? store.session.first_name : store.session.username; - }); - - }).catch(e => { - throw new Error("Failed to get session data: " + e.toString()); }); + if (!response.ok) { + throw new Error("Failed to get session data: " + response.statusText); + } + + /* Store session data */ + const rspJson = await response.json(); + store.session = { ...rspJson }; + store.userName = store.session.first_name ? store.session.first_name : store.session.username; } /** @@ -70,21 +65,17 @@ export async function oauthCallbackHandler(queryString) { * make sure that out user is known in the app database (basebox broker). After successful * login, this function must be called to do that. * - * @param username unique username of new user - * @param firstName first name of new user - * @param lastName last name of new user - * @returns {Promise} + * @throws Error if the user creation failed. */ -async function createUser(username, firstName, lastName) { +export async function createUser() { - gqlQuery(`query { + await gqlQuery(`mutation { createUser( - username: "${username}", - name: "${firstName} ${lastName}" - )` - ).catch(err => { - - }); - + username: "${store.session.username}", + name: "${store.session.first_name} ${store.session.last_name}" + ) { + username + } + }`); } \ No newline at end of file diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 2a0c619..f686087 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -7,6 +7,7 @@