diff --git a/client/package.json b/client/package.json index 981dbd0..0f73861 100644 --- a/client/package.json +++ b/client/package.json @@ -9,7 +9,9 @@ "lint": "vue-cli-service lint" }, "dependencies": { + "axios": "^0.23.0", "vue": "^3.0.0", + "vue-class-component": "^8.0.0-0", "vue-router": "^4.0.0-0", "vuex": "^4.0.0-0" }, diff --git a/client/src/assets/logo.png b/client/src/assets/logo.png index f3d2503..cf44c2a 100644 Binary files a/client/src/assets/logo.png and b/client/src/assets/logo.png differ diff --git a/client/src/components/HelloWorld.vue b/client/src/components/HelloWorld.vue index 6dffac8..878d09f 100644 --- a/client/src/components/HelloWorld.vue +++ b/client/src/components/HelloWorld.vue @@ -1,35 +1,6 @@ diff --git a/client/src/router/index.ts b/client/src/router/index.ts index a6021e1..e8520ab 100644 --- a/client/src/router/index.ts +++ b/client/src/router/index.ts @@ -1,5 +1,6 @@ import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' import Home from '../views/Home.vue' +import Login from '../views/Login.vue' const routes: Array = [ { @@ -7,6 +8,11 @@ const routes: Array = [ name: 'Home', component: Home }, + { + path: '/', + name: 'Login', + component: Login + }, { path: '/about', name: 'About', diff --git a/client/src/services/auth.service.ts b/client/src/services/auth.service.ts new file mode 100644 index 0000000..0f347cf --- /dev/null +++ b/client/src/services/auth.service.ts @@ -0,0 +1,35 @@ +import { User } from "@/types/user"; + +import axios from 'axios'; + +const API_URL = 'http://localhost:8080/api/auth/'; + +class AuthService { + login(user: User) { + return axios + .post(API_URL + 'signin', { + username: user.username, + password: user.password + }) + .then((response: any) => { + if (response.data.accessToken) { + localStorage.setItem('user', JSON.stringify(response.data)); + } + return response.data; + }); + } + + logout() { + localStorage.removeItem('user'); + } + + register(user: User) { + return axios.post(API_URL + 'signup', { + username: user.username, + email: user.email, + password: user.password + }); + } +} + +export default new AuthService(); diff --git a/client/src/services/data.service.ts b/client/src/services/data.service.ts new file mode 100644 index 0000000..9835d9a --- /dev/null +++ b/client/src/services/data.service.ts @@ -0,0 +1,10 @@ +export default function authHeader() { + let user = JSON.parse(localStorage.getItem('user')!); + + if (user && user.accessToken) { + return { Authorization: 'Bearer ' + user.accessToken }; + } else { + return {}; + } + } + \ No newline at end of file diff --git a/client/src/store/auth.module.ts b/client/src/store/auth.module.ts new file mode 100644 index 0000000..f67cae7 --- /dev/null +++ b/client/src/store/auth.module.ts @@ -0,0 +1,62 @@ +import AuthService from '@/services/auth.service'; +import { User } from '@/types/user'; + +const user = JSON.parse(localStorage.getItem('user')!); +const initialState = user + ? { status: { loggedIn: true }, user } + : { status: { loggedIn: false }, user: null }; + +export const auth = { + namespaced: true, + state: initialState, + actions: { + login({ commit }, user: User) { + return AuthService.login(user).then( + user => { + commit('loginSuccess', user); + return Promise.resolve(user); + }, + error => { + commit('loginFailure'); + return Promise.reject(error); + } + ); + }, + logout({ commit }) { + AuthService.logout(); + commit('logout'); + }, + register({ commit }, user) { + return AuthService.register(user).then( + response => { + commit('registerSuccess'); + return Promise.resolve(response.data); + }, + error => { + commit('registerFailure'); + return Promise.reject(error); + } + ); + } + }, + mutations: { + loginSuccess(state, user) { + state.status.loggedIn = true; + state.user = user; + }, + loginFailure(state) { + state.status.loggedIn = false; + state.user = null; + }, + logout(state) { + state.status.loggedIn = false; + state.user = null; + }, + registerSuccess(state) { + state.status.loggedIn = false; + }, + registerFailure(state) { + state.status.loggedIn = false; + } + } +}; diff --git a/client/src/store/index.ts b/client/src/store/index.ts index 5f05f19..9a32bbc 100644 --- a/client/src/store/index.ts +++ b/client/src/store/index.ts @@ -1,3 +1,4 @@ +import { auth } from "./auth.module"; import { createStore } from 'vuex' export default createStore({ @@ -8,5 +9,6 @@ export default createStore({ actions: { }, modules: { + auth } }) diff --git a/client/src/types/user.ts b/client/src/types/user.ts new file mode 100644 index 0000000..4f2aa2b --- /dev/null +++ b/client/src/types/user.ts @@ -0,0 +1,5 @@ +export class User { + public username?: String + public email?: String + public password?: String +} \ No newline at end of file diff --git a/client/src/views/Login.vue b/client/src/views/Login.vue new file mode 100644 index 0000000..13f8976 --- /dev/null +++ b/client/src/views/Login.vue @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file diff --git a/client/tsconfig.json b/client/tsconfig.json index 87673b7..1c27e2e 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -2,10 +2,11 @@ "compilerOptions": { "target": "es5", "module": "esnext", - "strict": true, + "strict": false, "jsx": "preserve", "importHelpers": true, "moduleResolution": "node", + "experimentalDecorators": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, diff --git a/client/yarn.lock b/client/yarn.lock index bc80c0e..8303f44 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -1564,6 +1564,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.23.0.tgz#b0fa5d0948a8d1d75e3d5635238b6c4625b05149" + integrity sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg== + dependencies: + follow-redirects "^1.14.4" + babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -3995,7 +4002,7 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.14.4: version "1.14.4" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== @@ -9350,6 +9357,11 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== +vue-class-component@^8.0.0-0: + version "8.0.0-rc.1" + resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-8.0.0-rc.1.tgz#db692cd97656eb9a08206c03d0b7398cdb1d9420" + integrity sha512-w1nMzsT/UdbDAXKqhwTmSoyuJzUXKrxLE77PCFVuC6syr8acdFDAq116xgvZh9UCuV0h+rlCtxXolr3Hi3HyPQ== + vue-eslint-parser@^7.0.0, vue-eslint-parser@^7.10.0: version "7.11.0" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz#214b5dea961007fcffb2ee65b8912307628d0daf"