logout handling
This commit is contained in:
parent
2ef22fd197
commit
cd7a727f0f
@ -17,6 +17,11 @@
|
|||||||
"name": "Userlist",
|
"name": "Userlist",
|
||||||
"to": "/userlist",
|
"to": "/userlist",
|
||||||
"icon": "fa-news"
|
"icon": "fa-news"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Logout",
|
||||||
|
"to": "/logout",
|
||||||
|
"icon": "fa-lock"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"description": "JS UI for Basispanel Server Management",
|
"description": "JS UI for Basispanel Server Management",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "WEBPACK_ENV=dev webpack-dev-server --inline --hot --open",
|
"serve": "WEBPACK_ENV=dev webpack-dev-server --inline --hot --host 0.0.0.0",
|
||||||
"dev": "WEBPACK_ENV=dev webpack --progress --colors --watch",
|
"dev": "WEBPACK_ENV=dev webpack --progress --colors --watch",
|
||||||
"build": "WEBPACK_ENV=production webpack --colors"
|
"build": "WEBPACK_ENV=production webpack --colors"
|
||||||
},
|
},
|
||||||
|
17
src/components/logout.vue
Normal file
17
src/components/logout.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
Sie werden ausgeloggt....
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'logout',
|
||||||
|
created() {
|
||||||
|
this.$store.commit('clearLogin');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$router.replace('/login');
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -2,15 +2,19 @@
|
|||||||
|
|
||||||
<div class="My-Table">
|
<div class="My-Table">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<thead>
|
||||||
<th v-for="(c, i) in columns" :key="i">{{ c.heading }}</th>
|
<tr>
|
||||||
</tr>
|
<th v-for="(c, i) in columns" :key="i">{{ c.heading }}</th>
|
||||||
<tr v-for="(r, ri) in rows" :key="ri">
|
</tr>
|
||||||
<td v-for="(c, ci) in columns" :key="ci">
|
</thead>
|
||||||
<span v-if="c.prop">{{ r[c.prop] }}</span>
|
<tbody is="transition-group" name="list">
|
||||||
<span v-else-if="c.render">{{ c.render(r) }}</span>
|
<tr v-for="(r, ri) in rows" :key="ri">
|
||||||
</td>
|
<td v-for="(c, ci) in columns" :key="ci + 'c'">
|
||||||
</tr>
|
<span v-if="c.prop">{{ r[c.prop] }}</span>
|
||||||
|
<span v-else-if="c.render">{{ c.render(r) }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -38,4 +42,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.list-item {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.list-enter-active, .list-leave-active {
|
||||||
|
transition: all 1s;
|
||||||
|
}
|
||||||
|
.list-enter, .list-leave-to /* .list-leave-active below version 2.1.8 */ {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="Scroll-Table">
|
<div class="Scroll-Table">
|
||||||
<my-table :columns="columns" :rows="rows"></my-table>
|
<my-table :columns="columns" :rows="rows"></my-table>
|
||||||
<div v-show="hasMore" v-if="!loading" v-observe-visibility="visibilityChanged">...</div>
|
<div v-if="loadingDelayed">loading...</div>
|
||||||
<div v-if="loading">loading...</div>
|
<div style="padding-left: 30%; padding-bottom: 100px;">
|
||||||
|
<span v-show="hasMore" v-if="!loadingDelayed" v-observe-visibility="visibilityChanged">...</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -56,15 +58,28 @@ export default {
|
|||||||
watch: {
|
watch: {
|
||||||
newRows(rows) {
|
newRows(rows) {
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
this.rows.push(row)
|
this.rowsToPush.push(row);
|
||||||
});
|
});
|
||||||
this.currentOffset += rows.length;
|
this.currentOffset += rows.length;
|
||||||
|
this.pushRows(); // for transition
|
||||||
|
},
|
||||||
|
loading(l) {
|
||||||
|
if (!l) {
|
||||||
|
// delay after loading for visibility observer
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loadingDelayed = false;
|
||||||
|
}, 200);
|
||||||
|
} else {
|
||||||
|
this.loadingDelayed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
rows: [ ],
|
rows: [ ],
|
||||||
currentOffset: this.offset
|
rowsToPush: [ ],
|
||||||
|
currentOffset: this.offset,
|
||||||
|
loadingDelayed: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -73,6 +88,15 @@ export default {
|
|||||||
// infinite scrolling
|
// infinite scrolling
|
||||||
this.handler(this.currentOffset, this.limit);
|
this.handler(this.currentOffset, this.limit);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
pushRows() {
|
||||||
|
let row = this.rowsToPush.shift();
|
||||||
|
if (row) {
|
||||||
|
this.rows.push(row);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.pushRows();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,7 @@ export default {
|
|||||||
.then(rows => {
|
.then(rows => {
|
||||||
this.hasMore = (rows.length >= limit);
|
this.hasMore = (rows.length >= limit);
|
||||||
this.newRows = rows;
|
this.newRows = rows;
|
||||||
setTimeout(() => {
|
this.loading = false;
|
||||||
this.loading = false;
|
|
||||||
}, 200); // for oberserver
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
147
src/main.js
147
src/main.js
@ -7,6 +7,7 @@ import JwtDecode from 'jwt-decode';
|
|||||||
import App from './app.vue';
|
import App from './app.vue';
|
||||||
import Dashboard from './components/dashboard.vue';
|
import Dashboard from './components/dashboard.vue';
|
||||||
import LoginForm from './components/forms/login.vue';
|
import LoginForm from './components/forms/login.vue';
|
||||||
|
import Logout from './components/logout.vue';
|
||||||
import Userlist from './components/userlist.vue';
|
import Userlist from './components/userlist.vue';
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
@ -25,6 +26,10 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/userlist',
|
path: '/userlist',
|
||||||
component: Userlist
|
component: Userlist
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/logout',
|
||||||
|
component: Logout
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -36,35 +41,41 @@ const store = new Vuex.Store({
|
|||||||
state: {
|
state: {
|
||||||
api: {},
|
api: {},
|
||||||
navigation: [],
|
navigation: [],
|
||||||
login: {},
|
persist: {
|
||||||
authToken: '',
|
login: {},
|
||||||
jwt: {},
|
authToken: '',
|
||||||
credentials: {}
|
jwt: {},
|
||||||
|
credentials: {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setAPI(state, payload) {
|
setAPI(state, payload) {
|
||||||
state.api = payload;
|
state.api = payload;
|
||||||
},
|
},
|
||||||
setNavigation(state, payload) {
|
setNavigation(state, payload) {
|
||||||
for (var i=0; i<payload.length; i++) {
|
for (var i = 0; i < payload.length; i++) {
|
||||||
state.navigation.push(payload[i]); // = payload;
|
state.navigation.push(payload[i]); // = payload;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setCredentials(state, payload) {
|
setCredentials(state, payload) {
|
||||||
state.credentials = {
|
state.persist.credentials = {
|
||||||
username: payload.username,
|
username: payload.username,
|
||||||
password: payload.password
|
password: payload.password
|
||||||
}
|
};
|
||||||
|
objectToPersist(state.persist, 'persistantStore');
|
||||||
},
|
},
|
||||||
setLogin(state, payload) {
|
setLogin(state, payload) {
|
||||||
state.login = payload.User;
|
state.persist.login = payload.User;
|
||||||
state.authToken = payload.AuthToken;
|
state.persist.authToken = payload.AuthToken;
|
||||||
state.jwt = JwtDecode(payload.AuthToken);
|
state.persist.jwt = JwtDecode(payload.AuthToken);
|
||||||
|
objectToPersist(state.persist, 'persistantStore');
|
||||||
},
|
},
|
||||||
clearLogin() {
|
clearLogin(state) {
|
||||||
state.login = {};
|
state.persist.login = {};
|
||||||
state.authToken = '';
|
state.persist.authToken = '';
|
||||||
state.jwt = {};
|
state.persist.jwt = {};
|
||||||
|
state.persist.credentials = {};
|
||||||
|
objectToPersist(state.persist, 'persistantStore');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -78,25 +89,25 @@ const store = new Vuex.Store({
|
|||||||
params: payload.params,
|
params: payload.params,
|
||||||
data: payload.data,
|
data: payload.data,
|
||||||
headers: {
|
headers: {
|
||||||
'X-Auth-Token': context.state.authToken
|
'X-Auth-Token': context.state.persist.authToken
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
console.log(response);
|
console.log(response);
|
||||||
resolve(response.data);
|
resolve(response.data);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.dir(error);
|
console.dir(error);
|
||||||
reject(error);
|
reject(error);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (payload.endpoint != 'login') {
|
if (payload.endpoint != 'login') {
|
||||||
// no jwt check for login call
|
// no jwt check for login call
|
||||||
|
|
||||||
// empty username = not logged in
|
// empty username = not logged in
|
||||||
if (!context.state.credentials.username) {
|
if (!context.state.persist.credentials.username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// show login page
|
// show login page
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
@ -105,7 +116,7 @@ const store = new Vuex.Store({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let now = Math.round(Date.now() / 1000);
|
let now = Math.round(Date.now() / 1000);
|
||||||
if ( context.state.jwt.exp < (now + 300) ) {
|
if (context.state.persist.jwt.exp < (now + 300)) {
|
||||||
// too old jwt, logout
|
// too old jwt, logout
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
context.commit('clearLogin');
|
context.commit('clearLogin');
|
||||||
@ -114,11 +125,11 @@ const store = new Vuex.Store({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (context.state.jwt.exp - 60) < now ) {
|
if ((context.state.persist.jwt.exp - 60) < now) {
|
||||||
// jwt near expire, get new one
|
// jwt near expire, get new one
|
||||||
console.log("getting new jwt");
|
console.log("getting new jwt");
|
||||||
|
|
||||||
return context.dispatch('login', context.state.credentials)
|
return context.dispatch('login', context.state.persist.credentials)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log("LOOOGIIIINNN");
|
console.log("LOOOGIIIINNN");
|
||||||
return doRequest();
|
return doRequest();
|
||||||
@ -144,43 +155,71 @@ const store = new Vuex.Store({
|
|||||||
resolve(data.User);
|
resolve(data.User);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error.response && error.response.data && error.response.data.error) {
|
if (error.response && error.response.data && error.response.data.error) {
|
||||||
reject(error.response.data.error);
|
reject(error.response.data.error);
|
||||||
} else {
|
} else {
|
||||||
reject([]);
|
reject([]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function objectToPersist(obj, key) {
|
||||||
|
try {
|
||||||
|
const serialized = JSON.stringify(obj);
|
||||||
|
localStorage.setItem(key ? key : 'persistant', serialized);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function persistToObject(key) {
|
||||||
|
try {
|
||||||
|
const serialized = localStorage.getItem(key ? key : 'persistant');
|
||||||
|
if (serialized === null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return JSON.parse(serialized);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get store persist part from localStorage
|
||||||
|
let persist = persistToObject('persistantStore');
|
||||||
|
if (persist) {
|
||||||
|
store.state.persist = persist;
|
||||||
|
}
|
||||||
|
|
||||||
// load init
|
// load init
|
||||||
Axios.get('conf/init.json')
|
Axios.get('conf/init.json')
|
||||||
.then(results => {
|
.then(results => {
|
||||||
// set navigation
|
// set navigation
|
||||||
if ( !Array.isArray(results.data.navigation) ) {
|
if (!Array.isArray(results.data.navigation)) {
|
||||||
alert('invalid data in: ' + this.src);
|
alert('invalid data in init.json');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.commit("setNavigation", results.data.navigation);
|
store.commit("setNavigation", results.data.navigation);
|
||||||
|
|
||||||
// set api config in store
|
// set api config in store
|
||||||
store.commit("setAPI", results.data.api);
|
store.commit("setAPI", results.data.api);
|
||||||
|
|
||||||
// load app, when init finishs
|
// load app, when init finishs
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#vue-app',
|
el: '#vue-app',
|
||||||
components: {
|
components: {
|
||||||
App
|
App
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
navItems: store.state.navigation
|
navItems: store.state.navigation
|
||||||
},
|
},
|
||||||
router,
|
router,
|
||||||
store
|
store
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
alert('error loading: ' + error.message);
|
alert('error loading: ' + error.message);
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user