diff --git a/.env b/.env index 1b5a6c0..06fc746 100644 --- a/.env +++ b/.env @@ -8,9 +8,4 @@ VUE_APP_AUTH_HOST="http://localhost:2000" VUE_APP_BACKEND_HOST="http://localhost:3000" #LocalStorage는 Edge 브라우저의 개발툴 > 응용프로그램 > 로컬 저장소에서 확인가능 -VUE_APP_SESSIONSTORAGE_JWT_NAME="access_token" -VUE_APP_SESSIONSTORAGE_REDIRECT_NAME = "RedirectPATH" - - -VUE_APP_TABLE_DEFAULT_PERPAGE = 10 -VUE_APP_TABLE_DEFAULT_TABLE_PAGE = 1 \ No newline at end of file +VUE_APP_TABLE_DEFAULT_PERPAGE = 10 \ No newline at end of file diff --git a/src/components/common/LoginComponent.vue b/src/components/LoginComponent.vue similarity index 56% rename from src/components/common/LoginComponent.vue rename to src/components/LoginComponent.vue index 88118c9..8996e90 100644 --- a/src/components/common/LoginComponent.vue +++ b/src/components/LoginComponent.vue @@ -42,18 +42,16 @@ Login - Reset + diff --git a/src/components/common/TableHeaderComponent b/src/components/common/TableHeaderComponent new file mode 100644 index 0000000..feede3a --- /dev/null +++ b/src/components/common/TableHeaderComponent @@ -0,0 +1,87 @@ + + + + + + + All + + + + + + + + + + 검색 + + + + + + + ~ + + 선택 + + + + + 줄수 + + + + + + + + diff --git a/src/components/common/TablePaginationComponent b/src/components/common/TablePaginationComponent new file mode 100644 index 0000000..280bb81 --- /dev/null +++ b/src/components/common/TablePaginationComponent @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/src/components/layout/HeaderLayout.vue b/src/components/layout/HeaderLayout.vue index d17de79..9ad0778 100644 --- a/src/components/layout/HeaderLayout.vue +++ b/src/components/layout/HeaderLayout.vue @@ -31,20 +31,51 @@ FA --> - - - - User - - Profile - Sign Out - + + + + + User + + Profile + Sign Out + + + Login {{ isAuthenticated }} + diff --git a/src/components/todo/InputComponent.vue b/src/components/todo/InputComponent.vue index b8ef7f4..dd6fa01 100644 --- a/src/components/todo/InputComponent.vue +++ b/src/components/todo/InputComponent.vue @@ -1,74 +1,58 @@ - - - - - - - {{ field.title.label }} - - {{ - validationContext.errors[0] - }} - - - - {{ field.content.label }} - - - {{ - validationContext.errors[0] - }} - - - - 입력 - Reset - - - - - + + + + + {{ field.title.label }} + + {{ + validationContext.errors[0] + }} + + + + {{ field.content.label }} + + + {{ + validationContext.errors[0] + }} + + + + 입력 + Reset + + + diff --git a/src/router/index.js b/src/router/index.js index b6660dd..aa54f7f 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,7 +1,7 @@ import Vue from 'vue' import VueRouter from 'vue-router' import HomeView from '../views/HomeView.vue' - +import store from '../store' Vue.use(VueRouter) const routes = [ @@ -33,8 +33,8 @@ const routes = [ component: () => import( /* webpackChunkName: "api", webpackPrefetch:true */ '@/views/todoView.vue' - ) - //meta: { requiredAuth: true } + ), + meta: { requiredAuth: true } } ] @@ -52,21 +52,6 @@ const router = new VueRouter({ // 1. 전역가드 : router.beforeEach((to, from, next) 이런식으로 전체에 대해 특정조건 (meta: { requiredAuth: true })으로 사용 // 2. 라우터 가드: 특정 Route Path아래에 직접선언-> beforeEach: function(to, from, next){} // 3. 컴포넌트 가드: 특정 vue 파일내에서 바로 선언해서 사용 :// view/Mypage.vue ( Mypage Components ) -// export default { -// name: "Mypage", -// beforeRouteEnter(to, from, next) { -// // Login 컴포넌트가 화면에 표시되기 전에 수행될 로직 -// // Login 컴포넌트는 아직 생성되지 않은 시점 -// }, -// beforeRouteUpdate(to, from, next) { -// // 화면에 표시된 컴포넌트가 변경될 때 수행될 로직 -// // `this`로 Login 컴포넌트를 접근할 수 있음 -// }, -// beforeRouteLeave(to, from, next) { -// // Login 컴포넌트를 화면에 표시한 url 값이 변경되기 직전의 로직 -// // `this`로 Login 컴포넌트를 접근할 수 있음 -// }, -// } // 로그인 처리 과정용 // to : 이동할 url 정보가 담긴 라우터 객체 // from : 현재 url 정보가 담긴 라우터 객체 @@ -74,26 +59,21 @@ const router = new VueRouter({ //여기에서 login은 path가 아니라 name에서 찾는다 //router.beforeEach()를 호출하고 나면 모든 라우팅이 대기 상태가 된다 router.beforeEach((to, from, next) => { - console.log('라우딩 대기') //1. routes 설정에서 meta: { requiredAuth: true } 가 선언된 경우 - if (to.matched.some((routeRecord) => routeRecord.meta.requiredAuth)) { + if (to.matched.some((route) => route.meta.requiredAuth)) { //2. 로그인 인증 않된 경우 - //sessionStorage Access-Token이 없으면 Login페이지로 전송 - if (!sessionStorage.getItem(process.env.VUE_APP_SESSIONSTORAGE_JWT_NAME)) { - console.log(from.path + ' => 3. Login 페이지 이동 => 로그인 페이지') - //로그인 성공 후 이동할 URL 저장 - sessionStorage.setItem( - process.env.VUE_APP_SESSIONSTORAGE_REDIRECT_NAME, - to.path - ) - next({ name: 'login' }) + //console.log(store.getters) + //console.log(store.getters['AuthStore/isAuthenticated']) + if (!store.getters['AuthStore/isAuthenticated']) { + console.log(from.name + ' => 3. To[' + to.name + '] => 로그인') + next({ name: 'login', params: { return_url: to.name } }) } else { //3. 로그인 인증완료 - console.log(from.path + ' => 2. 이미인증완료 => ' + to.path) + console.log(from.name + ' => 2. 이미인증완료 => ' + to.name) next() } } else { - console.log(from.path + ' => 1. 인증요구 없음 => ' + to.path) + console.log(from.name + ' => 1. 인증요구 없음 => ' + to.name) next() } }) diff --git a/src/store/index.js b/src/store/index.js index d0e0c20..e3bc789 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,12 +1,13 @@ import Vue from 'vue' import Vuex from 'vuex' +import AuthStore from './modules/auth' +import TodoStore from './modules/todo' Vue.use(Vuex) export default new Vuex.Store({ - state: {}, - getters: {}, - mutations: {}, - actions: {}, - modules: {} + modules: { + AuthStore, + TodoStore + } }) diff --git a/src/store/modules/auth.js b/src/store/modules/auth.js new file mode 100644 index 0000000..09131d0 --- /dev/null +++ b/src/store/modules/auth.js @@ -0,0 +1,97 @@ +import axios from 'axios' +import jwt from './jwt' + +//참조: https://yamoo9.github.io/axios/guide/interceptors.html +const authAxios = axios.create({ + baseURL: process.env.VUE_APP_AUTH_HOST, + headers: { 'content-type': 'application/json' } +}) +authAxios.interceptors.request.use( + (config) => jwt.getAuthorizationHeader(config), + (error) => { + // Do something with request error + Promise.reject(error) + } +) +authAxios.defaults.headers.post['Content-Type'] = + 'application/x-www-form-urlencoded' + +// count state 속성 추가 +const state = { + token: { + accessToken: jwt.getToken() + }, // 토큰정보 + isAuthenticated: jwt.isAuthenticated() +} +const getters = { + getAccessToken: function (state) { + return state.token.accessToken + }, + isAuthenticated: function (state) { + return state.isAuthenticated + } +} +const mutations = { + login: function (state, payload = {}) { + state.token.accessToken = payload.accessToken + state.isAuthenticated = true + jwt.saveToken(payload.accessToken) + }, + logout: function (state) { + state.token.accessToken = '' + state.isAuthenticated = false + jwt.destroyToken() + } +} +const actions = { + login: function (context, payload) { + let params = { + email: payload.email, + password: payload.password + } + return new Promise((resolve, reject) => { + authAxios + .post('/auth/login', params) + .then((response) => { + const { data } = response + context.commit('login', { + accessToken: data.accessToken + }) + resolve(response) + }) + .catch((error) => { + reject(error) + }) + }) + }, + logout: function (context, payload) { + return new Promise((resolve) => { + setTimeout(function () { + context.commit('logout', payload) + resolve({}) + }, 1000) + }) + }, + register: function (context, payload) { + let params = { + email: payload.email, + password: payload.password, + name: payload.name + } + return new Promise((resolve, reject) => { + authAxios + .post('/user/register', params) + .then((response) => { + const { data } = response + context.commit('login', { + accessToken: data.accessToken + }) + resolve(response) + }) + .catch((error) => { + reject(error) + }) + }) + } +} +export default { namespaced: true, state, getters, mutations, actions } diff --git a/src/store/modules/jwt.js b/src/store/modules/jwt.js new file mode 100644 index 0000000..0e288a4 --- /dev/null +++ b/src/store/modules/jwt.js @@ -0,0 +1,28 @@ +const Payload_KEY_NAME = 'access_token' +const getToken = () => { + return window.localStorage.getItem(Payload_KEY_NAME) +} +const saveToken = (token) => { + window.localStorage.setItem(Payload_KEY_NAME, token) +} +const destroyToken = () => { + window.localStorage.removeItem(Payload_KEY_NAME) +} +const isAuthenticated = () => { + return !!getToken() +} + +const getAuthorizationHeader = (config) => { + //로그인이 되었는지 확인후 Request시 헤더에 로그인정보 추가하기 위함 + if (isAuthenticated) { + config.headers.common['Authorization'] = getToken() + } + return config +} +export default { + getToken, + saveToken, + destroyToken, + isAuthenticated, + getAuthorizationHeader +} diff --git a/src/store/modules/todo.js b/src/store/modules/todo.js new file mode 100644 index 0000000..d4b7c1e --- /dev/null +++ b/src/store/modules/todo.js @@ -0,0 +1,55 @@ +import axios from 'axios' +import jwt from './jwt' + +//참조: https://yamoo9.github.io/axios/guide/interceptors.html +const todoAxios = axios.create({ + baseURL: process.env.VUE_APP_BACKEND_HOST, + headers: { 'content-type': 'application/json' } +}) +todoAxios.interceptors.request.use( + (config) => jwt.getAuthorizationHeader(config), + (error) => { + // Do something with request error + Promise.reject(error) + } +) +todoAxios.defaults.headers.post['Content-Type'] = + 'application/x-www-form-urlencoded' + +// count state 속성 추가 +const state = { + total: 0, + rows: [] +} +const getters = { + getTotal: function (state) { + return state.total + }, + getRows: function (state) { + return state.rows + } +} +const mutations = { + setData: function (state, data) { + state.total = data.total + state.rows = data.rows + } +} +const actions = { + setData: function (context, params) { + console.log(params) + return new Promise((resolve, reject) => { + todoAxios + .get('/todo', params) + .then((response) => { + const { data } = response + context.commit('setData', data) + resolve(response) + }) + .catch((error) => { + reject(error) + }) + }) + } +} +export default { namespaced: true, state, getters, mutations, actions } diff --git a/src/views/loginView.vue b/src/views/loginView.vue index f696a02..6c39e06 100644 --- a/src/views/loginView.vue +++ b/src/views/loginView.vue @@ -1,15 +1,23 @@ - + - + diff --git a/src/views/todoView.vue b/src/views/todoView.vue index a4e2dcd..5ea33b2 100644 --- a/src/views/todoView.vue +++ b/src/views/todoView.vue @@ -3,18 +3,48 @@ - 입력 - + + 입력 + + + +