started the authentication
basic routing
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
VUE_APP_TITLE=GelegeApp - [DEV]
|
||||
|
||||
VUE_APP_BASE_URL= http://localhost:1337/
|
||||
|
||||
@@ -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'
|
||||
|
||||
Generated
+20
-2
@@ -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
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -1,11 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
modules: {}
|
||||
});
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about</h1>
|
||||
</div>
|
||||
</template>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user