diff --git a/package-lock.json b/package-lock.json
index 4a1fcce0..43a886e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1843,6 +1843,16 @@
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true
},
+ "axios": {
+ "version": "0.18.0",
+ "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
+ "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
+ "dev": true,
+ "requires": {
+ "follow-redirects": "^1.3.0",
+ "is-buffer": "^1.1.5"
+ }
+ },
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -2418,6 +2428,11 @@
"integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
"dev": true
},
+ "bulma": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.1.tgz",
+ "integrity": "sha512-wRSO2LXB+qI9Pyz2id+uZr4quz5aftSN7Ay1ysr1+krzVp3utD+Ci4CeKuZdrYGc800t65b7heXBL6qw2Wo/lQ=="
+ },
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
@@ -11830,6 +11845,12 @@
"vue-style-loader": "^4.1.0"
}
},
+ "vue-router": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz",
+ "integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w==",
+ "dev": true
+ },
"vue-style-loader": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
diff --git a/package.json b/package.json
index f79a3547..be98bd4b 100644
--- a/package.json
+++ b/package.json
@@ -8,12 +8,15 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
+ "bulma": "^0.7.1",
"vue": "^2.5.17"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.0.1",
"@vue/cli-plugin-eslint": "^3.0.1",
"@vue/cli-service": "^3.0.1",
+ "axios": "^0.18.0",
+ "vue-router": "^3.0.1",
"vue-template-compiler": "^2.5.17"
},
"eslintConfig": {
diff --git a/siteconfig.json b/siteconfig.json
new file mode 100644
index 00000000..57d746ed
--- /dev/null
+++ b/siteconfig.json
@@ -0,0 +1,3 @@
+{
+ "API_URL": "http://localhost:8080/api/v1/"
+}
diff --git a/src/App.vue b/src/App.vue
index fcc56627..32c1b5b3 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,28 +1,23 @@
-
-
-
-
+
+
Test
+
+
diff --git a/src/auth/index.js b/src/auth/index.js
new file mode 100644
index 00000000..7ecf2315
--- /dev/null
+++ b/src/auth/index.js
@@ -0,0 +1,91 @@
+import {HTTP} from '../http-common'
+import router from '../router'
+// const API_URL = 'http://localhost:8082/api/v1/'
+// const LOGIN_URL = 'http://localhost:8082/login'
+
+export default {
+
+ user: {
+ authenticated: false,
+ infos: {}
+ },
+
+ login (context, creds, redirect) {
+ HTTP.post('login', {
+ username: creds.username,
+ password: creds.password
+ })
+ .then(response => {
+ // Save the token to local storage for later use
+ localStorage.removeItem('token') // Delete an eventually preexisting old token
+ localStorage.setItem('token', response.data.token)
+
+ // Tell others the user is autheticated
+ this.user.authenticated = true
+ this.getUserInfos()
+
+ // Hide the loader
+ context.loading = false
+
+ // Redirect if nessecary
+ if (redirect) {
+ router.push({ name: redirect })
+ }
+ })
+ .catch(e => {
+ // Hide the loader
+ context.loading = false
+ if (e.response) {
+ context.error = e.response.data.message
+ if (e.response.status === 401) {
+ context.error = context.translate('login').wrong
+ }
+ }
+ })
+ },
+
+ logout () {
+ localStorage.removeItem('token')
+ router.push({ name: 'login' })
+ this.user.authenticated = false
+ },
+
+ checkAuth () {
+ let jwt = localStorage.getItem('token')
+ this.getUserInfos()
+ this.user.authenticated = false
+ if (jwt) {
+ let infos = this.user.infos
+ let ts = Math.round((new Date()).getTime() / 1000)
+ if (infos.exp >= ts) {
+ this.user.authenticated = true
+ }
+ }
+ },
+
+ getUserInfos () {
+ let jwt = localStorage.getItem('token')
+ if (jwt) {
+ this.user.infos = this.parseJwt(localStorage.getItem('token'))
+ return this.parseJwt(localStorage.getItem('token'))
+ } else {
+ return {}
+ }
+ },
+
+ parseJwt (token) {
+ let base64Url = token.split('.')[1]
+ let base64 = base64Url.replace('-', '+').replace('_', '/')
+ return JSON.parse(window.atob(base64))
+ },
+
+ getAuthHeader () {
+ return {
+ 'Authorization': 'Bearer ' + localStorage.getItem('token')
+ }
+ },
+
+ getToken () {
+ return localStorage.getItem('token')
+ }
+}
diff --git a/src/http-common/index.js b/src/http-common/index.js
new file mode 100644
index 00000000..297ee29a
--- /dev/null
+++ b/src/http-common/index.js
@@ -0,0 +1,6 @@
+import axios from 'axios'
+let config = require('../../siteconfig.json')
+
+export const HTTP = axios.create({
+ baseURL: config.API_URL
+})
diff --git a/src/main.js b/src/main.js
index fca74cfc..0eb05997 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,8 +1,14 @@
import Vue from 'vue'
import App from './App.vue'
+import router from './router'
+import auth from './auth'
Vue.config.productionTip = false
+// Check the user's auth status when the app starts
+auth.checkAuth()
+
new Vue({
+ router,
render: h => h(App)
}).$mount('#app')
diff --git a/src/router/index.js b/src/router/index.js
new file mode 100644
index 00000000..662836bf
--- /dev/null
+++ b/src/router/index.js
@@ -0,0 +1,22 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+
+import HomeComponent from '@/components/Home'
+import LoginComponent from '@/components/Login'
+
+Vue.use(Router)
+
+export default new Router({
+ routes: [
+ {
+ path: '/',
+ name: 'home',
+ component: HomeComponent
+ },
+ {
+ path: '/login',
+ name: 'login',
+ component: LoginComponent
+ }
+ ]
+})
\ No newline at end of file