Store_Vuex init...
This commit is contained in:
parent
8790bcc516
commit
22543d0f15
2
.env
2
.env
@ -5,7 +5,7 @@
|
|||||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||||
VUE_APP_AUTH_HOST="http://localhost:2000"
|
VUE_APP_AUTH_HOST="http://localhost:2000"
|
||||||
|
|
||||||
VUE_APP_BACKEND_HOST="http://localhost:3000"
|
VUE_APP_TODO_HOST="http://localhost:3000"
|
||||||
|
|
||||||
#LocalStorage는 Edge 브라우저의 개발툴 > 응용프로그램 > 로컬 저장소에서 확인가능
|
#LocalStorage는 Edge 브라우저의 개발툴 > 응용프로그램 > 로컬 저장소에서 확인가능
|
||||||
VUE_APP_TABLE_DEFAULT_PERPAGE = 10
|
VUE_APP_TABLE_DEFAULT_PERPAGE = 10
|
||||||
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
// 참고 : https://kdydesign.github.io/2019/04/06/vuejs-vuex-helper/
|
// 참고 : https://kdydesign.github.io/2019/04/06/vuejs-vuex-helper/
|
||||||
import authService from '../service/authService'
|
import authService from '../service/auth.service'
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
//console.log(this.$route)
|
//console.log(this.$route)
|
||||||
@ -80,25 +80,18 @@ export default {
|
|||||||
getValidationState({ dirty, validated, valid = null }) {
|
getValidationState({ dirty, validated, valid = null }) {
|
||||||
return dirty || validated ? valid : null
|
return dirty || validated ? valid : null
|
||||||
},
|
},
|
||||||
async onSubmit() {
|
onSubmit() {
|
||||||
//인증서버에서 인증코드받기
|
try {
|
||||||
authService
|
authService.login({
|
||||||
.post('/auth/login', {
|
|
||||||
email: this.form.email,
|
email: this.form.email,
|
||||||
password: this.form.password
|
password: this.form.password
|
||||||
})
|
})
|
||||||
.then(() => {
|
this.$router.push({
|
||||||
this.$router
|
name: this.$route.params.return_url || 'home'
|
||||||
.push({
|
|
||||||
name: this.$route.params.return_url || 'home'
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
throw new Error('router 오류\n' + +e.response.data.message)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
alert(e)
|
|
||||||
})
|
})
|
||||||
|
} catch (e) {
|
||||||
|
alert(e.response.data.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -136,6 +136,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import todoService from '@/service/todo.service'
|
||||||
import { createNamespacedHelpers } from 'vuex'
|
import { createNamespacedHelpers } from 'vuex'
|
||||||
const todoStore = createNamespacedHelpers('TodoStore')
|
const todoStore = createNamespacedHelpers('TodoStore')
|
||||||
// 참조 : https://vuejsexamples.com/vuejs-tables-and-select-all-checkbox/
|
// 참조 : https://vuejsexamples.com/vuejs-tables-and-select-all-checkbox/
|
||||||
@ -247,8 +248,8 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async setDatas(page = 1) {
|
async setDatas(page = 1) {
|
||||||
await this.$store
|
try {
|
||||||
.dispatch('TodoStore/setDatas', {
|
const datas = await todoService.setDatas({
|
||||||
page: page,
|
page: page,
|
||||||
perPage: this.perPage,
|
perPage: this.perPage,
|
||||||
sortBy: this.sortBy,
|
sortBy: this.sortBy,
|
||||||
@ -260,9 +261,11 @@ export default {
|
|||||||
filterDateStart: this.filterDateStart,
|
filterDateStart: this.filterDateStart,
|
||||||
filterDateEnd: this.filterDateEnd
|
filterDateEnd: this.filterDateEnd
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
console.log(datas)
|
||||||
alert(e)
|
} catch (e) {
|
||||||
})
|
console.log(e)
|
||||||
|
alert(e.response.data.message)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
searchClick() {
|
searchClick() {
|
||||||
this.setDatas()
|
this.setDatas()
|
||||||
|
|||||||
53
src/interceptors/auth.Iterceptor.js
Normal file
53
src/interceptors/auth.Iterceptor.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import api from './auth.api'
|
||||||
|
import jwt from '../service/jwt'
|
||||||
|
//참조: https://www.bezkoder.com/vue-refresh-token/
|
||||||
|
const setup = (store) => {
|
||||||
|
//API Request 전 처리용
|
||||||
|
api.defaults.headers.post['Content-Type'] =
|
||||||
|
'application/x-www-form-urlencoded'
|
||||||
|
//Request 처리용
|
||||||
|
api.interceptors.request.use(
|
||||||
|
(config) => jwt.getAuthorizationHeader(config),
|
||||||
|
(error) => {
|
||||||
|
// Do something with request error
|
||||||
|
Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//AccessToken이 만료된경우 다시 받기위한 함수
|
||||||
|
const reloadAccessToken = async (originalConfig) => {
|
||||||
|
// Access Token이 expired,오류로 인한 response 401 답볍을 받은경우
|
||||||
|
originalConfig._retry = true
|
||||||
|
try {
|
||||||
|
//Refresh Token으로 다시 Access Token 재생성 후 로그인 다시하라고 오류보냄
|
||||||
|
await api
|
||||||
|
.post('/auth/reload', {
|
||||||
|
refresh_token: jwt.getRefreshToken()
|
||||||
|
})
|
||||||
|
.then((rs) => {
|
||||||
|
store.dispatch('reload', rs.data.access_token)
|
||||||
|
})
|
||||||
|
return api(originalConfig)
|
||||||
|
} catch (_error) {
|
||||||
|
return Promise.reject(_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Response 처리용
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
console.log('AUTH API Call 성공=>' + response)
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
async (err) => {
|
||||||
|
// Do something with response error
|
||||||
|
const originalConfig = err.config
|
||||||
|
if (originalConfig.url !== '/auth/login' && err.response) {
|
||||||
|
if (err.response.status === 401 && !originalConfig._retry) {
|
||||||
|
return await reloadAccessToken(originalConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default setup
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
const instance = axios.create({
|
const authAPI = axios.create({
|
||||||
baseURL: process.env.VUE_APP_AUTH_HOST,
|
baseURL: process.env.VUE_APP_AUTH_HOST,
|
||||||
headers: { 'Content-type': 'application/json' }
|
headers: { 'Content-type': 'application/json' }
|
||||||
})
|
})
|
||||||
|
|
||||||
export default instance
|
export default authAPI
|
||||||
58
src/interceptors/todo.Iterceptor.js
Normal file
58
src/interceptors/todo.Iterceptor.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import api from './auth.api'
|
||||||
|
import jwt from '../service/jwt'
|
||||||
|
//참조: https://www.bezkoder.com/vue-refresh-token/
|
||||||
|
const setup = (store) => {
|
||||||
|
//API Request 전 처리용
|
||||||
|
api.defaults.headers.post['Content-Type'] =
|
||||||
|
'application/x-www-form-urlencoded'
|
||||||
|
//Request 처리용
|
||||||
|
api.interceptors.request.use(
|
||||||
|
(config) => jwt.getAuthorizationHeader(config),
|
||||||
|
(error) => {
|
||||||
|
// Do something with request error
|
||||||
|
Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//AccessToken이 만료된경우 다시 받기위한 함수
|
||||||
|
const reloadAccessToken = async (originalConfig) => {
|
||||||
|
// Access Token이 expired,오류로 인한 response 401 답볍을 받은경우
|
||||||
|
originalConfig._retry = true
|
||||||
|
try {
|
||||||
|
//Refresh Token으로 다시 Access Token 재생성 후 로그인 다시하라고 오류보냄
|
||||||
|
await api
|
||||||
|
.post('/auth/reload', {
|
||||||
|
refresh_token: jwt.getRefreshToken()
|
||||||
|
})
|
||||||
|
.then((rs) => {
|
||||||
|
store.dispatch('reload', rs.data.access_token)
|
||||||
|
})
|
||||||
|
return api(originalConfig)
|
||||||
|
} catch (_error) {
|
||||||
|
return Promise.reject(_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Response 처리용
|
||||||
|
api.interceptors.response.use(
|
||||||
|
async (response) => {
|
||||||
|
switch (response.config.url) {
|
||||||
|
case '/todo':
|
||||||
|
await store.dispatch('setDatas', response.data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
async (err) => {
|
||||||
|
// Do something with response error
|
||||||
|
const originalConfig = err.config
|
||||||
|
if (originalConfig.url !== '/auth/login' && err.response) {
|
||||||
|
if (err.response.status === 401 && !originalConfig._retry) {
|
||||||
|
return await reloadAccessToken(originalConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('TODO API Call 오류=>' + err)
|
||||||
|
return Promise.reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default setup
|
||||||
6
src/interceptors/todo.api.js
Normal file
6
src/interceptors/todo.api.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
const todoAPI = axios.create({
|
||||||
|
baseURL: process.env.VUE_APP_TODO_HOST,
|
||||||
|
headers: { 'Content-type': 'application/json' }
|
||||||
|
})
|
||||||
|
export default todoAPI
|
||||||
@ -33,8 +33,8 @@ const routes = [
|
|||||||
component: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "api", webpackPrefetch:true */ '@/views/todoView.vue'
|
/* webpackChunkName: "api", webpackPrefetch:true */ '@/views/todoView.vue'
|
||||||
),
|
)
|
||||||
meta: { requiredAuth: true }
|
//meta: { requiredAuth: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -62,9 +62,8 @@ router.beforeEach((to, from, next) => {
|
|||||||
//1. routes 설정에서 meta: { requiredAuth: true } 가 선언된 경우
|
//1. routes 설정에서 meta: { requiredAuth: true } 가 선언된 경우
|
||||||
if (to.matched.some((route) => route.meta.requiredAuth)) {
|
if (to.matched.some((route) => route.meta.requiredAuth)) {
|
||||||
//2. 로그인 체크용
|
//2. 로그인 체크용
|
||||||
const access_token = jwt.getToken('access_token')
|
const access_token = jwt.getAccessToken()
|
||||||
const refresh_token = jwt.getToken('refresh_token')
|
if (access_token === null && jwt.getRefreshToken() !== null) {
|
||||||
if (access_token === null && refresh_token !== null) {
|
|
||||||
//refreshToken은 있고 accessToken이 없을 경우 토큰 재발급 요청
|
//refreshToken은 있고 accessToken이 없을 경우 토큰 재발급 요청
|
||||||
this.$store.dispatch('refreshToken')
|
this.$store.dispatch('refreshToken')
|
||||||
} else if (access_token) {
|
} else if (access_token) {
|
||||||
|
|||||||
7
src/service/auth.service.js
Normal file
7
src/service/auth.service.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import api from '../interceptors/auth.api'
|
||||||
|
class AuthService {
|
||||||
|
async login(params) {
|
||||||
|
return await api.get('/auth/login', params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default new AuthService()
|
||||||
7
src/service/todo.service.js
Normal file
7
src/service/todo.service.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import api from '../interceptors/todo.api'
|
||||||
|
class TodoService {
|
||||||
|
async setDatas(params) {
|
||||||
|
return await api.get('/todo', { params: params })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default new TodoService()
|
||||||
26
src/service/token.service.js
Normal file
26
src/service/token.service.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
class TokenService {
|
||||||
|
getLocalRefreshToken() {
|
||||||
|
const user = JSON.parse(localStorage.getItem('user'))
|
||||||
|
return user?.refreshToken
|
||||||
|
}
|
||||||
|
getLocalAccessToken() {
|
||||||
|
const user = JSON.parse(localStorage.getItem('user'))
|
||||||
|
return user?.accessToken
|
||||||
|
}
|
||||||
|
updateLocalAccessToken(token) {
|
||||||
|
let user = JSON.parse(localStorage.getItem('user'))
|
||||||
|
user.accessToken = token
|
||||||
|
localStorage.setItem('user', JSON.stringify(user))
|
||||||
|
}
|
||||||
|
getUser() {
|
||||||
|
return JSON.parse(localStorage.getItem('user'))
|
||||||
|
}
|
||||||
|
setUser(user) {
|
||||||
|
console.log(JSON.stringify(user))
|
||||||
|
localStorage.setItem('user', JSON.stringify(user))
|
||||||
|
}
|
||||||
|
removeUser() {
|
||||||
|
localStorage.removeItem('user')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default new TokenService()
|
||||||
@ -1,46 +0,0 @@
|
|||||||
import authService from '../service/authService'
|
|
||||||
import jwt from '../service/jwt'
|
|
||||||
//참조: https://www.bezkoder.com/vue-refresh-token/
|
|
||||||
const setup = (store) => {
|
|
||||||
//API Request 전 처리용
|
|
||||||
authService.defaults.headers.post['Content-Type'] =
|
|
||||||
'application/x-www-form-urlencoded'
|
|
||||||
//Request 처리용
|
|
||||||
authService.interceptors.request.use(
|
|
||||||
(config) => jwt.getAuthorizationHeader(config),
|
|
||||||
(error) => {
|
|
||||||
// Do something with request error
|
|
||||||
Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
//Response 처리용
|
|
||||||
authService.interceptors.response.use(
|
|
||||||
(res) => {
|
|
||||||
console.log('AuthService Call 성공=>' + res)
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
async (err) => {
|
|
||||||
// Do something with response error
|
|
||||||
const originalConfig = err.config
|
|
||||||
if (originalConfig.url !== '/auth/login' && err.response) {
|
|
||||||
// Access Token이 expired,오류로 인한 response 401 답볍을 받은경우
|
|
||||||
if (err.response.status === 401 && !originalConfig._retry) {
|
|
||||||
originalConfig._retry = true
|
|
||||||
try {
|
|
||||||
//Refresh Token으로 다시 Access Token 재생성 후 로그인 다시하라고 오류보냄
|
|
||||||
const rs = await authService.post('/auth/reload', {
|
|
||||||
refresh_token: jwt.getRefreshToken()
|
|
||||||
})
|
|
||||||
const { access_token } = rs.data
|
|
||||||
store.dispatch('auth/reload', access_token)
|
|
||||||
return authService(originalConfig)
|
|
||||||
} catch (_error) {
|
|
||||||
return Promise.reject(_error)
|
|
||||||
}
|
|
||||||
} //401처리
|
|
||||||
}
|
|
||||||
Promise.reject(err.response.data.message)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default { setup }
|
|
||||||
@ -1,11 +1,15 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import AuthStore from './authStore'
|
import AuthStore from './auth.store'
|
||||||
import AuthInterceptors from './authIterceptors'
|
import TodoStore from './todo.store'
|
||||||
import TodoStore from './todoStore'
|
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
AuthInterceptors(AuthStore)
|
|
||||||
|
//인터셉터 정의 및 Storage 연동
|
||||||
|
import setupAuthInterceptor from '../interceptors/auth.Iterceptor'
|
||||||
|
setupAuthInterceptor(AuthStore)
|
||||||
|
import setupTodoInterceptor from '../interceptors/todo.Iterceptor'
|
||||||
|
setupTodoInterceptor(TodoStore)
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
modules: {
|
modules: {
|
||||||
|
|||||||
24
src/store/todo.store.js
Normal file
24
src/store/todo.store.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const state = {
|
||||||
|
total: 0,
|
||||||
|
rows: []
|
||||||
|
}
|
||||||
|
const getters = {
|
||||||
|
getTotal: function (state) {
|
||||||
|
return state.total
|
||||||
|
},
|
||||||
|
getRows: function (state) {
|
||||||
|
return state.rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const mutations = {
|
||||||
|
setDatas: function (state, datas) {
|
||||||
|
state.total = datas.total
|
||||||
|
state.rows = datas.rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const actions = {
|
||||||
|
setDatas: function (context, datas) {
|
||||||
|
context.commit('setDatas', datas.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default { namespaced: true, state, getters, mutations, actions }
|
||||||
@ -1,55 +0,0 @@
|
|||||||
import axios from 'axios'
|
|
||||||
import jwt from '../service/jwt'
|
|
||||||
|
|
||||||
//참조: https://yamoo9.github.io/axios/guide/interceptors.html
|
|
||||||
const apiServer = axios.create({
|
|
||||||
baseURL: process.env.VUE_APP_BACKEND_HOST,
|
|
||||||
headers: { 'content-type': 'application/json' }
|
|
||||||
})
|
|
||||||
apiServer.interceptors.request.use(
|
|
||||||
(config) => jwt.getAuthorizationHeader(config),
|
|
||||||
(error) => {
|
|
||||||
// Do something with request error
|
|
||||||
Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
apiServer.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 = {
|
|
||||||
setDatas: function (state, data) {
|
|
||||||
state.total = data.total
|
|
||||||
state.rows = data.rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const actions = {
|
|
||||||
setDatas: async function (context, params) {
|
|
||||||
console.log(params)
|
|
||||||
//주의 .get의 parameter는 { params: params} 처럼 보내야함
|
|
||||||
return await apiServer
|
|
||||||
.get('/todo', { params: params })
|
|
||||||
.then((response) => {
|
|
||||||
console.log(response)
|
|
||||||
const { data } = response
|
|
||||||
context.commit('setDatas', data)
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
//throw new Error('todo List 오류\n' + e.response.data.message)
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default { namespaced: true, state, getters, mutations, actions }
|
|
||||||
Loading…
Reference in New Issue
Block a user