improved login page / login status

This commit is contained in:
Tobias Kurze
2019-11-26 15:25:36 +01:00
parent a9a94d6f3c
commit 42366def40
6 changed files with 191 additions and 61 deletions

74
package-lock.json generated
View File

@@ -2529,6 +2529,11 @@
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
"integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==" "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg=="
}, },
"argh": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/argh/-/argh-0.1.4.tgz",
"integrity": "sha1-PrTWEpc/xrbcbvM49W91nyrFw6Y="
},
"argparse": { "argparse": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -3020,8 +3025,7 @@
"bluebird": { "bluebird": {
"version": "3.5.3", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
"integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
"dev": true
}, },
"bn.js": { "bn.js": {
"version": "4.11.8", "version": "4.11.8",
@@ -3504,6 +3508,11 @@
} }
} }
}, },
"camelify": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/camelify/-/camelify-0.0.2.tgz",
"integrity": "sha1-4UNHKrbvJbiUpOhcNUyZd6sfHhU="
},
"caniuse-api": { "caniuse-api": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@@ -3840,6 +3849,11 @@
"simple-swizzle": "^0.2.2" "simple-swizzle": "^0.2.2"
} }
}, },
"colors": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
"integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w="
},
"combined-stream": { "combined-stream": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
@@ -5923,6 +5937,22 @@
"locate-path": "^3.0.0" "locate-path": "^3.0.0"
} }
}, },
"findup": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz",
"integrity": "sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs=",
"requires": {
"colors": "~0.6.0-1",
"commander": "~2.1.0"
},
"dependencies": {
"commander": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz",
"integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E="
}
}
},
"fkill": { "fkill": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/fkill/-/fkill-6.1.0.tgz", "resolved": "https://registry.npmjs.org/fkill/-/fkill-6.1.0.tgz",
@@ -9114,9 +9144,9 @@
} }
}, },
"node-sass": { "node-sass": {
"version": "4.12.0", "version": "4.13.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz",
"integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==",
"requires": { "requires": {
"async-foreach": "^0.1.3", "async-foreach": "^0.1.3",
"chalk": "^1.1.1", "chalk": "^1.1.1",
@@ -9125,7 +9155,7 @@
"get-stdin": "^4.0.1", "get-stdin": "^4.0.1",
"glob": "^7.0.3", "glob": "^7.0.3",
"in-publish": "^2.0.0", "in-publish": "^2.0.0",
"lodash": "^4.17.11", "lodash": "^4.17.15",
"meow": "^3.7.0", "meow": "^3.7.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"nan": "^2.13.2", "nan": "^2.13.2",
@@ -9168,6 +9198,11 @@
"which": "^1.2.9" "which": "^1.2.9"
} }
}, },
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lru-cache": { "lru-cache": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@@ -12343,6 +12378,33 @@
"path-key": "^2.0.0" "path-key": "^2.0.0"
} }
}, },
"npm-sass": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/npm-sass/-/npm-sass-2.3.0.tgz",
"integrity": "sha512-/Msbyq/rsqMJslcxRrRNdxTR2VUTEXETNsYhPWw/lSb+QgpnDdWi4LOocfEpCleDPLzP7FnkM7w9Bc0mKP3xcg==",
"requires": {
"argh": "^0.1.4",
"bluebird": "^3.5.1",
"camelify": "0.0.2",
"findup": "^0.1.5",
"glob": "^6.0.1",
"node-sass": "^4.9.0"
},
"dependencies": {
"glob": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
"integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=",
"requires": {
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
}
}
},
"npmlog": { "npmlog": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",

View File

@@ -19,8 +19,9 @@
"i": "^0.3.6", "i": "^0.3.6",
"jquery": "^3.3.1", "jquery": "^3.3.1",
"js-cookie": "^2.2.0", "js-cookie": "^2.2.0",
"node-sass": "^4.12.0", "node-sass": "^4.13.0",
"npm": "^6.9.0", "npm": "^6.9.0",
"npm-sass": "^2.3.0",
"popper.js": "^1.15.0", "popper.js": "^1.15.0",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"vee-validate": "^2.2.4", "vee-validate": "^2.2.4",

View File

@@ -28,8 +28,6 @@
<b-collapse id="nav-collapse" is-nav> <b-collapse id="nav-collapse" is-nav>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item to="/about">About</b-nav-item> <b-nav-item to="/about">About</b-nav-item>
<b-nav-item v-if="authenticated" to="/logout">Logout</b-nav-item>
<b-nav-item v-else="authenticated" to="/login">Login</b-nav-item>
<b-nav-item v-if="authenticated" :to="{name: 'rooms'}">{{ $t('Rooms') }}</b-nav-item> <b-nav-item v-if="authenticated" :to="{name: 'rooms'}">{{ $t('Rooms') }}</b-nav-item>
<b-nav-item v-if="authenticated" :to="{name: 'recorders'}">{{ $t('Recorders') }}</b-nav-item> <b-nav-item v-if="authenticated" :to="{name: 'recorders'}">{{ $t('Recorders') }}</b-nav-item>
@@ -57,18 +55,25 @@
</b-dropdown-item> </b-dropdown-item>
</b-nav-item-dropdown> </b-nav-item-dropdown>
<b-nav-item-dropdown right> <b-nav-item-dropdown v-if="authenticated" right>
<!-- Using 'button-content' slot --> <!-- Using 'button-content' slot -->
<template slot="button-content"><em>User</em></template> <template slot="button-content"><em>User</em></template>
<b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item> <b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item>
<b-dropdown-item to="/logout">Sign Out</b-dropdown-item> <b-dropdown-item to="/logout" @click.prevent="logout()">Sign Out</b-dropdown-item>
</b-nav-item-dropdown> </b-nav-item-dropdown>
<b-nav-item v-else to="/login">Login</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-collapse> </b-collapse>
</b-navbar> </b-navbar>
<span>({{tokenValidity}})</span> | <span v-if="tokenValidity">({{$t('Session will timeout in: ')}}{{tokenValidity}})</span>
<span>({{refreshTokenValidity}})</span> <span v-else>{{$t('Session has expired!')}} <a v-if="refreshTokenValidity" href="~"
@click.prevent="refreshToken()">{{$t('Click here to refresh session')}}</a></span>
<span v-if="refreshTokenValidity">&nbsp;|&nbsp;({{refreshTokenValidity}})
<input type="checkbox" id="auto_renew_cb" v-model="autoRenewSession">
<label for="auto_renew_cb">{{$t('auto renew session')}}</label>
</span>
<span v-else>{{$t('Can\'t renew session please login again!')}}</span>
</div> </div>
<router-view/> <router-view/>
</div> </div>
@@ -94,6 +99,7 @@
langs: ['de', 'en', 'es'], langs: ['de', 'en', 'es'],
dismissSecs: 5, dismissSecs: 5,
dismissCountDown: 0, dismissCountDown: 0,
autoRenewSession: false,
}; };
}, },
methods: { methods: {
@@ -105,6 +111,14 @@
countDownChanged(dismissCountDown) { countDownChanged(dismissCountDown) {
this.dismissCountDown = dismissCountDown; this.dismissCountDown = dismissCountDown;
}, },
logout() {
this.$store.dispatch('logout', {revokeRefreshToken: true});
this.$router.push({name: 'home'});
},
refreshToken() {
this.$store.dispatch('refreshToken');
}
}, },
mounted() { mounted() {
EventBus.$on('failedLoadingRecorders', (msg) => { EventBus.$on('failedLoadingRecorders', (msg) => {
@@ -119,17 +133,31 @@
this.$nextTick(() => { this.$nextTick(() => {
window.setInterval(() => { window.setInterval(() => {
//this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token)); //this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token));
this.tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token); let tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token);
this.refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token);
//this.tokenValidity = this.tokenValidity.format('mm:ss');
let refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token);
// this.$log.debug(this.$store.state); // this.$log.debug(this.$store.state);
if (this.tokenValidity < 50 && this.refreshTokenValidity > 30 && !this.refreshFailed) { if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) {
this.$store.dispatch('refreshToken'); // renew access token this.$store.dispatch('refreshToken'); // renew access token
} }
if(this.refreshFailed){ if (this.autoRenewSession && this.refreshFailed) {
this.$store.dispatch('resetToken'); // delete all token info if refresh fails this.$store.dispatch('resetToken'); // delete all token info if refresh fails
this.$router.push({name: 'login'}); this.$router.push({name: 'login'});
this.refreshFailed = false; this.refreshFailed = false;
} }
if (isNaN(tokenValidity)) {
this.tokenValidity = false;
} else {
this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5);
}
if (isNaN(tokenValidity)) {
this.refreshTokenValidity = false;
} else {
this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8);
}
}, 1000); }, 1000);
}); });

View File

@@ -23,6 +23,10 @@ export function authenticate(userData: any) {
return axios.post(`${API_URL}/auth/login`, userData); return axios.post(`${API_URL}/auth/login`, userData);
} }
export function revokeRefreshKey(jwt: any) {
return axios.post(`${API_URL}/auth/revokeRefreshToken`, { headers: { Authorization: `Bearer ${jwt}` } });
}
export function register(userData: any) { export function register(userData: any) {
return axios.post(`${API_URL}/auth/register`, userData); return axios.post(`${API_URL}/auth/register`, userData);
} }

View File

@@ -49,7 +49,8 @@
</div> </div>
<div v-else> <div v-else>
<h1>{{ $t('You are already logged in!') }}</h1> <h1>{{ $t('You are already logged in!') }}</h1>
<p><a href="some_logout_url">{{$t('logout')}}</a></p> <h2>{{$t('Redirecting you to')}} <router-link :to="{name: redirectTarget}">{{redirectTarget}}</router-link> {{$t('in')}} {{redirectTime}} {{$t('seconds')}}.</h2>
<p><a href="" @click.prevent="logout()">{{$t('logout')}}</a></p>
</div> </div>
</div> </div>
</template> </template>
@@ -64,6 +65,9 @@
email: '', email: '',
password: '', password: '',
errorMsg: '', errorMsg: '',
redirectMsg: '',
redirectTarget: 'profile',
redirectTime: 5,
loginProviders: [], loginProviders: [],
}; };
}, },
@@ -79,6 +83,10 @@
oidc_login() { oidc_login() {
this.$store.dispatch('oidc_login', '\\oidc_login_redirection'); this.$store.dispatch('oidc_login', '\\oidc_login_redirection');
}, },
logout() {
this.$store.dispatch('logout', {revokeRefreshToken: true});
this.$router.push({name: 'home'});
},
}, },
mounted() { mounted() {
// this.$parent.$data.isLoading = true; // this.$parent.$data.isLoading = true;
@@ -104,6 +112,22 @@
this.$cookies.remove('tokens'); this.$cookies.remove('tokens');
} }
this.$log.debug(this.$cookies.keys()); this.$log.debug(this.$cookies.keys());
this.$nextTick(() => {
if (this.authenticated) {
if (this.$route.query.redirectionTarget) {
this.redirectTarget = this.$route.query.redirectionTarget;
}
let interval = window.setInterval(() => {
console.log(this.redirectTime);
this.redirectTime = this.redirectTime - 1;
if (this.redirectTime < 0) {
clearInterval(interval);
this.$router.push({name: this.redirectTarget});
}
}, 1000);
}
});
}, },
beforeDestroy() { beforeDestroy() {
EventBus.$off('failedRegistering'); EventBus.$off('failedRegistering');

View File

@@ -14,7 +14,7 @@ import {
postNewSurvey, postNewSurvey,
authenticate, authenticate,
register, register,
oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, revokeRefreshKey,
} from '@/api'; } from '@/api';
import {isValidJwt, EventBus} from '@/utils'; import {isValidJwt, EventBus} from '@/utils';
@@ -184,6 +184,17 @@ const actions = {
EventBus.$emit('failedAuthentication', error); EventBus.$emit('failedAuthentication', error);
}); });
}, },
logout(context: any, revokeRefreshToken: any) {
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
if(revokeRefreshToken){
return revokeRefreshKey(context.state.access_token)
.catch((error) => {
Vue.$log.warn('Error Authenticating (Could not revoke refresh token): ', error);
EventBus.$emit('failedRevokingRefreshToken', error);
});
}
//this.clearAll();
},
oidc_login(context: any, redirectionUrl: any) { oidc_login(context: any, redirectionUrl: any) {
// context.commit('setUserData', { userData }); // context.commit('setUserData', { userData });
return oidc_login(redirectionUrl) return oidc_login(redirectionUrl)