Some work on login process

* Forward already autheticated users
* If not auteticated forward back to login
* Clear current user if no valid session
This commit is contained in:
Ferdinand Thiessen 2020-11-09 03:40:51 +01:00
parent 8c1dffc003
commit b479e3ad48
8 changed files with 97 additions and 55 deletions

19
package-lock.json generated
View File

@ -1719,6 +1719,12 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
"integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
"dev": true
},
"vue-router": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.2.0.tgz",
"integrity": "sha512-khkrcUIzMcI1rDcNtqkvLwfRFzB97GmJEsPAQdj7t/VvpGhmXLOkUfhc+Ah8CvpSXGXwuWuQO+x8Sy/xDhXZIA==",
"dev": true
}
}
},
@ -4262,9 +4268,9 @@
}
},
"core-js": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.7.0.tgz",
"integrity": "sha512-NwS7fI5M5B85EwpWuIwJN4i/fbisQUwLwiSNUWeXlkAZ0sbBjLEvLvFLf1uzAUV66PcEPt4xCGCmOZSxVf3xzA=="
},
"core-js-compat": {
"version": "3.6.5",
@ -13650,10 +13656,9 @@
}
},
"vue-router": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.2.0.tgz",
"integrity": "sha512-khkrcUIzMcI1rDcNtqkvLwfRFzB97GmJEsPAQdj7t/VvpGhmXLOkUfhc+Ah8CvpSXGXwuWuQO+x8Sy/xDhXZIA==",
"dev": true
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.3.2.tgz",
"integrity": "sha512-5sEbcfb7MW8mY8lbUVbF4kgcipGXsagkM/X+pb6n0MhjP+RorWIUTPAPSqgPaiPOxVCXgAItBl8Vwz8vq78faA=="
},
"vue-server-renderer": {
"version": "2.6.12",

View File

@ -13,8 +13,9 @@
"@quasar/extras": "^1.9.10",
"@vue/composition-api": "^0.6.4",
"axios": "^0.18.1",
"core-js": "^3.6.5",
"quasar": "^1.14.3"
"core-js": "^3.7.0",
"quasar": "^1.14.3",
"vue-router": "3.3.2"
},
"devDependencies": {
"@quasar/app": "^2.1.6",
@ -34,15 +35,14 @@
"last 10 Chrome versions",
"last 10 Firefox versions",
"last 4 Edge versions",
"last 7 Safari versions",
"last 6 Safari versions",
"last 8 Android versions",
"last 8 ChromeAndroid versions",
"last 8 FirefoxAndroid versions",
"last 10 iOS versions",
"last 5 Opera versions"
"last 10 iOS versions"
],
"engines": {
"node": ">= 10.18.1",
"node": ">= 11.0.0",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
}

View File

@ -36,10 +36,13 @@ export default boot<Store<StateInterface>>(({ Vue, store }) => {
error => {
if (error) {
const e = <AxiosError>error;
if (e.code === 'ECONNABORTED' || e.response && e.response.status === 502) {
if (
e.code === 'ECONNABORTED' ||
(e.response && e.response.status === 502)
) {
store.commit('session/setOffline', true);
} else if (e.response && e.response.status == 401) {
return store.dispatch('session/clearup');
return store.dispatch('session/clearCurrent');
}
}
return Promise.reject(error);

View File

@ -35,7 +35,13 @@ export default boot<Store<StateInterface>>(({ router, store }) => {
next({ name: 'login', query: { redirect: to.fullPath } });
}
} else {
if (store.state.user.currentUser && !to.params['logout']) {
// Called login while already logged in
void next({ name: 'user-main' });
} else {
// Not logged in or from logout
next();
}
}
});
});

View File

@ -105,7 +105,7 @@
import EssentialLink from 'components/navigation/EssentialLink.vue';
import ShortCutLink from 'components/navigation/ShortCutLink.vue';
import BackendOffline from 'components/loading/BackendOffline.vue';
import { Screen } from 'quasar';
import { Screen, Loading } from 'quasar';
import { defineComponent, ref, computed } from '@vue/composition-api';
import { Store } from 'vuex';
import { StateInterface } from 'src/store';
@ -180,11 +180,11 @@ export default defineComponent({
});
function logout() {
const store = <Store<StateInterface>>ctx.root.$store;
store
.dispatch('session/logout', store.state.session.currentSession?.token)
.catch(error => {
console.warn(error);
Loading.show({ message: 'Session wird abgemeldet' });
(<Store<StateInterface>>ctx.root.$store)
.dispatch('session/logout')
.finally(() => {
Loading.hide();
});
}

View File

@ -35,10 +35,14 @@
<script lang="ts">
import { defineComponent, ref } from '@vue/composition-api';
import { Loading } from 'quasar';
export default defineComponent({
// name: 'PageName'
setup(_, { root }) {
const mainRoute = { name: 'user-main' };
/* Stuff for the real login page */
const userid = ref('');
const password = ref('');
const rules = [
@ -46,13 +50,22 @@ export default defineComponent({
];
function doLogin() {
Loading.show({
message: 'Du wirst angemeldet'
});
root.$store
.dispatch('session/login', {
userid: userid.value,
password: password.value
})
.catch(error => {
console.warn(error);
.then(() => {
const x = root.$route.query['redirect'];
void root.$router.replace(
typeof x === 'string' ? { path: x } : mainRoute
);
})
.finally(() => {
Loading.hide();
});
}

View File

@ -4,7 +4,7 @@ import { StateInterface } from 'src/store';
import { axios } from 'src/boot/axios';
import { AxiosError, AxiosResponse } from 'axios';
import { Router } from 'src/router';
import { LocalStorage, Loading } from 'quasar';
import { LocalStorage } from 'quasar';
export interface SessionInterface {
currentSession?: FG.Session;
@ -13,7 +13,11 @@ export interface SessionInterface {
backendOffline: boolean;
}
function loadFromLocal() {
/**
* Load current session from LocalStorage
* Used when we were already authenticated using this browser
*/
function loadCurrentSession() {
const session = LocalStorage.getItem<FG.Session>('currentSession');
if (session) session.expires = new Date(session.expires);
return session;
@ -21,7 +25,7 @@ function loadFromLocal() {
const state: SessionInterface = {
sessions: [],
currentSession: loadFromLocal() || undefined,
currentSession: loadCurrentSession() || undefined,
loading: false,
backendOffline: false
};
@ -47,11 +51,13 @@ const mutations: MutationTree<SessionInterface> = {
};
const actions: ActionTree<SessionInterface, StateInterface> = {
/** Used to authenticate the user
* Setting current Session, User and Permissions.
* @param param0 Context
* @param data Credentitals
*/
login({ commit }, data: LoginData) {
Loading.show({
message: 'Du wirst angemeldet'
});
void axios
return axios
.post('/auth', data)
.then((response: AxiosResponse<LoginResponse>) => {
response.data.session.expires = new Date(response.data.session.expires);
@ -60,38 +66,38 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
commit('user/setCurrentPermissions', response.data.permissions, {
root: true
});
})
.catch(error => console.warn(error))
.finally(() => {
void Router.push({ name: 'user-main' });
Loading.hide();
});
},
/**
* Logout from current session
* Alias of deleteSession with current session as target
*/
logout({ dispatch, rootState }) {
Loading.show({ message: 'Session wird abgemeldet' });
dispatch('deleteSession', rootState.session.currentSession?.token).finally(
() => {
Loading.hide();
if (rootState.session.currentSession) {
dispatch('deleteSession', rootState.session.currentSession.token).catch(
error => {
console.log(error);
void dispatch('clearCurrent', false);
}
);
} else {
void dispatch('clearCurrent', false);
}
},
/**
* Delete a given session
*/
deleteSession({ commit, dispatch, rootState }, token: string | null) {
if (token === null) return;
deleteSession({ commit, dispatch, rootState }, token: string) {
commit('setLoading', true);
axios
.delete(`/auth/${token}`)
.then(() => {
if (token === rootState.session.currentSession?.token) {
void dispatch('clearup');
void dispatch('clearCurrent', false);
} else {
commit('getSessions');
dispatch('getSessions').catch(error => {
throw error;
});
}
})
.catch((error: AxiosError) => {
@ -101,15 +107,23 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
commit('setLoading', false);
});
},
clearup({ commit }) {
/**
* Clear current session and logged in user
*/
clearCurrent({ commit }, redirect = true) {
void Router.push({
name: 'login',
query: redirect ? { redirect: Router.currentRoute.fullPath } : {},
params: { logout: 'true' }
}).then(() => {
commit('clearCurrentSession');
commit('user/clearCurrentUser', null, { root: true });
void Router.push({ name: 'login' });
});
},
/**
* Get all sessions from current User
*/
getSessions({ commit, state, dispatch }) {
getSessions({ commit, state }) {
commit('setLoading', true);
axios
.get('/auth')
@ -122,11 +136,11 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
return session.token === state.currentSession?.token;
});
if (currentSession) {
void dispatch('setCurrentSession', currentSession);
commit('setCurrentSession', currentSession);
}
})
.catch(error => {
console.exception(error);
throw error;
})
.finally(() => {
commit('setLoading', false);

View File

@ -2,6 +2,7 @@
"extends": "@quasar/app/tsconfig-preset",
"compilerOptions": {
"types": ["node", "webpack-env", "@quasar/app"],
"baseUrl": "."
"baseUrl": ".",
"lib": ["DOM", "ES2019"]
}
}