1 Commits
Author SHA1 Message Date
Torben Indorf e2568a1bbe started the authentication
basic routing
2020-02-09 09:48:43 +01:00
19 changed files with 326 additions and 61 deletions
+4
View File
@@ -0,0 +1,4 @@
VUE_APP_TITLE=GelegeApp - [DEV]
VUE_APP_BASE_URL= http://localhost:1337/
-1
View File
@@ -7,7 +7,6 @@ module.exports = {
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'comma-dangle': ['error', 'never']
},
parserOptions: {
parser: '@typescript-eslint/parser'
+20 -2
View File
@@ -5417,8 +5417,7 @@
"flatted": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
"dev": true
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg=="
},
"flush-write-stream": {
"version": "1.1.1",
@@ -7517,6 +7516,11 @@
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
},
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"lodash.transform": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz",
@@ -11661,6 +11665,20 @@
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.2.tgz",
"integrity": "sha512-ha3jNLJqNhhrAemDXcmMJMKf1Zu4sybMPr9KxJIuOpVcsDQlTBYLLladav2U+g1AvdYDG5Gs0xBTb0M5pXXYFQ=="
},
"vuex-class": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/vuex-class/-/vuex-class-0.3.2.tgz",
"integrity": "sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ=="
},
"vuex-persist": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/vuex-persist/-/vuex-persist-2.2.0.tgz",
"integrity": "sha512-o/qbBeMcKZZqMvCXc7kfIew/5cjHxlP1f53rx5YYp3r2tk2kxXYK/UZumxKn7OXywlurl2r0mgkuBzH6nIWFjw==",
"requires": {
"flatted": "^2.0.0",
"lodash.merge": "^4.6.2"
}
},
"watchpack": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
+4 -2
View File
@@ -20,8 +20,10 @@
"vue": "^2.6.10",
"vue-class-component": "^7.0.2",
"vue-property-decorator": "^8.3.0",
"vue-router": "^3.1.3",
"vuex": "^3.1.2"
"vue-router": "^3.1.5",
"vuex": "^3.1.2",
"vuex-class": "^0.3.2",
"vuex-persist": "^2.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.1.0",
+24
View File
@@ -0,0 +1,24 @@
import axios, {AxiosInstance} from 'axios';
/**
* Auth repository that provides authentication api methods
*/
export default class AuthRepository {
protected axiosClient!: AxiosInstance;
private baseURL = process.env.VUE_APP_BASE_URL;
constructor() {
this.createHttpClient();
}
private createHttpClient() {
this.axiosClient = axios.create({
baseURL: `${this.baseURL}`
});
}
public async login(payload: { username: string, password: string }): Promise<any> {
return this.axiosClient.post('auth/loginUser', payload);
}
}
+18
View File
@@ -0,0 +1,18 @@
import AuthRepository from '@/api/AuthRepository';
const repositories: any = {
auth: { Repository: AuthRepository, instance: null }
};
/**
* Factory to create repositories. All created repositories are singleton instances.
*/
export const RepositoryFactory = {
get: (name: string) => {
if (repositories[name].instance) {
return repositories[name].instance;
} else {
return new repositories[name].Repository();
}
}
};
+18
View File
@@ -0,0 +1,18 @@
import store from '@/store/store'
export default class AuthGuard {
/**
* Checks if the token is available. If no token is set, redirect user to login_view.
* @param to
* @param from
* @param next
* @param permission
*/
public static async checkRouteAccess(to: any, from: any, next: any) {
if (store.getters['auth/token']) {
next();
} else {
next({name: 'login'});
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ import Vue from 'vue';
import Ionic, { IonicVueRouter } from '@ionic/vue';
import App from './App.vue';
import router from './router';
import store from './store';
import store from './store/store';
import '@ionic/core/css/core.css';
import '@ionic/core/css/ionic.bundle.css';
+45 -21
View File
@@ -1,30 +1,54 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import HelloWorld from '../components/HelloWorld.vue';
import { IonicVueRouter } from '@ionic/vue';
import {IonicVueRouter} from '@ionic/vue';
import LoginView from "@/views/Login.view.vue";
import HomeView from "@/views/Home.view.vue";
import AreaSelectionView from "@/views/AreaSelection.view.vue";
import MapOverviewView from "@/views/MapOverview.view.vue";
import AuthGuard from "@/helpers/AuthGuard";
import Router from 'vue-router';
Vue.use(IonicVueRouter);
const routes = [
{
path: '/',
name: 'home',
component: HelloWorld
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// Handle NavigationDuplicated stack error:
// https://github.com/vuejs/vue-router/issues/2881#issuecomment-520554378
const originalPush = Router.prototype.push;
// @ts-ignore
IonicVueRouter.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) {
return originalPush.call(this, location, onResolve, onReject);
}
];
// @ts-ignore
return originalPush.call(this, location).catch((err) => err);
};
const router = new IonicVueRouter({
export default new IonicVueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
routes: [
{
path: '/login',
name: 'login',
component: LoginView
},
{
path: '/home',
component: HomeView,
beforeEnter: (to: any, from: any, next: any) => AuthGuard.checkRouteAccess(to, from, next),
children: [
{
path: 'areaSelection',
name: 'areaSelection',
component: AreaSelectionView
}, {
path: 'mapOverview',
name: 'mapOverview',
component: MapOverviewView
}
]
},
{
path: '*',
redirect: {name: 'login'},
}
]
});
export default router;
+50
View File
@@ -0,0 +1,50 @@
import { ActionTree, Module } from 'vuex';
import { RepositoryFactory } from '@/api/RepositoryFactory';
import AuthRepository from '@/api/AuthRepository';
const authRepository: AuthRepository = RepositoryFactory.get('auth');
const store = {
token: undefined,
isAdmin: false,
lastLogin: undefined
};
const actions: ActionTree<any, any> = {
loginAction: async ({ commit }, payload: { username: string, password: string }): Promise<any> => {
const response = await authRepository.login(payload);
if (response && response.data.token) {
commit('saveToken', response.data.token);
}
return response;
},
};
const mutations = {
saveToken: (state: any, token: any) => {
state.token = token;
state.lastLogin = new Date();
},
clearToken: (state: any) => {
state.token = null;
state.lastLogin = null;
},
saveAdminPermission: (state: any, isAdmin: boolean) => state.isAdmin = isAdmin
};
const getters = {
token: (state: any) => state.token,
lastLogin: (state: any) => state.lastLogin,
isAdmin: (state: any) => state.isAdmin
};
const authStore: Module<any, any> = {
state: store,
actions,
mutations,
getters
};
export default authStore;
-11
View File
@@ -1,11 +0,0 @@
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {}
});
+30
View File
@@ -0,0 +1,30 @@
import Vue from 'vue';
import Vuex from 'vuex';
import VuexPersistence from 'vuex-persist';
import authStore from "@/store/auth.store";
Vue.use(Vuex);
// set up persistence storage plugin
const vuexPersistence = new VuexPersistence({
key: process.env.VUE_APP_TITLE,
storage: window.localStorage,
reducer: (state: any) => ({
auth: {
token: state.auth.token,
user: state.auth.user
}
}),
filter: (mutation) => ['auth/saveLogin'].includes(mutation.type)
});
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {
auth: {
namespaced: true,
...authStore
}
}
});
-5
View File
@@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about</h1>
</div>
</template>
+23
View File
@@ -0,0 +1,23 @@
<template>
<div>
AreaSelection
<ion-button @click="goToLogin"></ion-button>
</div>
</template>
<script lang="ts">
import {Component, Vue} from "vue-property-decorator";
@Component
export default class AreaSelectionView extends Vue {
public goToLogin() {
this.$router.push({name: 'login'});
}
}
</script>
<style scoped>
</style>
+18
View File
@@ -0,0 +1,18 @@
<template>
<div>
<ion-vue-router/>
</div>
</template>
<script lang="ts">
import {Component, Vue} from "vue-property-decorator";
@Component
export default class HomeView extends Vue {
}
</script>
<style scoped>
</style>
-14
View File
@@ -1,14 +0,0 @@
<template>
<div class="home">
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue';
export default {
name: 'home',
components: {}
};
</script>
+39
View File
@@ -0,0 +1,39 @@
<template>
<div>
<div>
<ion-button @click="loginClicked">Login</ion-button>
</div>
</div>
</template>
<script lang="ts">
import {Component, Vue} from "vue-property-decorator";
import { namespace } from 'vuex-class';
const AuthStore = namespace('auth');
@Component
export default class LoginView extends Vue {
@AuthStore.Action('loginAction')
public login!: (payload: { email: string, password: string }) => any;
public async loginClicked() {
const response = await this.login({
email: 't.indorf@28apps.de',
password: 'test'
});
if (response.status === 200) {
await this.$router.push({name: 'areaSelection'});
} else {
// TODO: Show error!
}
}
}
</script>
<style scoped>
</style>
+17
View File
@@ -0,0 +1,17 @@
<template>
<div>
</div>
</template>
<script lang="ts">
import {Component, Vue} from "vue-property-decorator";
@Component
export default class MapOverviewView extends Vue {
}
</script>
<style scoped>
</style>
+15 -4
View File
@@ -12,11 +12,20 @@
"sourceMap": true,
"resolveJsonModule": true,
"baseUrl": ".",
"types": ["webpack-env"],
"types": [
"webpack-env"
],
"paths": {
"@/*": ["src/*"]
"@/*": [
"src/*"
]
},
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
@@ -25,5 +34,7 @@
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": ["node_modules"]
"exclude": [
"node_modules"
]
}