[Vue.js] 토큰 기반 인증(#2. 인증을 위한 프로젝트 구조 살피기)
하수도키
·2020. 7. 27. 13:29
2020/10/31 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증 (#7. 자동 로그인)
2020/10/31 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증 catch 사용 (#6. 에러 처리)
2020/10/30 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증(#5. 유저 로그아웃)
2020/10/28 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증(#4. 유저 로그인)
2020/08/30 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증(#3. 사용자 등록)
2020/07/27 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증(#2. 인증을 위한 프로젝트 구조 살피기)
2020/07/24 - [개발일기/Vue.js] - [Vue.js] 토큰 기반 인증(#1. 인증소개)
[Vue.js] 토큰 기반 인증(#2. 인증을 위한 프로젝트 구조 살피기)
- 이제 코드를 통해 알아보자.
- 기본적으로
vue
,vuex
에 대한 기초 지식이 필요하다. - 몰라도 코드를 보면 알 수 있을 것 같긴 하다. : )
시작 코드 살펴보기
-
초기 프로젝트 세팅은 이전 포스팅을 참고 [Vue.js] Vue CLI 설치 및 세팅
-
App.vue
파일을 열고 아래 코드를 작성 해보자.- 아래와 같이
global.scss
따로 작성하여 불러와도 되고 style
내용을 다 작성해도 된다.
- 아래와 같이
// App.vue
<template>
<div id="app">
<app-nav />
<router-view class="page" />
</div>
</template>
<script>
import AppNav from './components/AppNav'
export default {
components: { AppNav }
}
</script>
<style lang="scss">
@import './assets/styles/global.scss';
.page {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
min-height: calc(100vh - 56px);
}
</style>
// src/assets/styles/global.scss
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
padding: 0em;
margin: 0em;
}
a:visited {
color: #2c3e50;
}
.button,
button {
display: flex;
align-items: center;
justify-content: center;
width: 5em;
height: 2em;
margin: 0.5em;
border-radius: 5px;
background: linear-gradient(to right, #16c0b0, #84cf6a);
font-size: 1em;
color: white;
border: none;
outline: none;
}
form {
display: flex;
align-items: center;
flex-direction: column;
width: 15em;
margin-bottom: 2em;
p {
color: red;
}
}
input {
display: block;
box-sizing: border-box;
width: 100%;
height: 2.6em;
padding: 0.5em;
margin-bottom: 1em;
font: 1em 'Avenir', Helvetica, sans-serif;
}
h1 {
margin-top: 0;
}
-
위
App.vue
를 보면AppNav
라는 컴포넌트가 있는데 이것도 만들자.// src/components/AppNav <template> <div id="nav"> <router-link to="/"> Home </router-link> <router-link to="/dashboard"> Dashboard </router-link> </div> </template>
-
AppNav
를 보니 link/
,/dashboard
가 보인다. -
이 2개의 링크 페이지를 작성하고, 라우터도 연결해보자.
-
우선 라우터를 연결하자.
router.js
파일을 살펴보자.
// src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import Dashboard from "../views/Dashboard.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/dashboard",
name: "dashboard",
component: Dashboard,
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
- 위에
router.js
파일을 보니 import가 된 2개의 vue 파일이 눈에 띈다. Home
,Dashboard
역시 만들어주자.
// src/views/Home.vue
<template>
<div class="home">
<h1>Welcome to the App!</h1>
</div>
</template>
<script>
export default {};
</script>
// src/views/Dashboard.vue
<template>
<div>
<h1>Dashboard</h1>
<template v-if="!isLoading">
<EventCard v-for="event in events" :key="event.id" :event="event" />
</template>
<p v-else>
Loading events
</p>
</div>
</template>
<script>
import axios from "axios";
import EventCard from "../components/EventCard";
export default {
components: { EventCard },
data() {
return {
isLoading: true,
events: [],
};
},
created() {
axios.get("//localhost:3000/dashboard").then(({ data }) => {
this.events = data.events.events;
this.isLoading = false;
});
},
};
</script>
- 와...또 보인다 import 되는것들을 살펴보자.
axios
,EventCard
를 만들어야 한다.axios
는 라이브러르로 설치하고EventCard
만 만들면 된다.axios
설치하는 법부터 살펴보자.- 터미널에서 아래 명령어를 입력, 그럼 끝!
npm install axios
server.js
와db
디렉토리도 만들어보자.events.json
에서events
를 불러오고user.json
에서user
를 관리할 예정이다.- 이 부분은 서버쪽 코드(벡엔드 담당)이며 간단하게 작성된 예제이다. 실무에서는 절대 사용할 수없고 흐름을 이해하는데 초점을 두면 되겠다.
- 서버쪽 코드에 필요한 라이브러리들을 먼저 설치하고, 파일 생성해보자.
npm install jsonwebtoken cors body-parser express
// /server.js
const express = require("express");
const jwt = require("jsonwebtoken");
const cors = require("cors");
const bodyParser = require("body-parser");
const fs = require("fs");
const events = require("./db/events.json");
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.get("/", (req, res) => {
res.json({
message: "Welcome to the API.",
});
});
app.get("/dashboard", (req, res) => {
res.json({
events: events,
});
});
app.post("/register", (req, res) => {
if (req.body) {
const user = {
name: req.body.name,
email: req.body.email,
password: req.body.password,
// In a production app, you'll want to encrypt the password
};
const data = JSON.stringify(user, null, 2);
var dbUserEmail = require("./db/user.json").email;
if (dbUserEmail === req.body.email) {
res.sendStatus(400);
} else {
fs.writeFile("./db/user.json", data, (err) => {
if (err) {
console.log(err + data);
} else {
const token = jwt.sign({ user }, "the_secret_key");
// In a production app, you'll want the secret key to be an environment variable
res.json({
token,
email: user.email,
name: user.name,
});
}
});
}
} else {
res.sendStatus(400);
}
});
app.post("/login", (req, res) => {
const userDB = fs.readFileSync("./db/user.json");
const userInfo = JSON.parse(userDB);
if (
req.body &&
req.body.email === userInfo.email &&
req.body.password === userInfo.password
) {
const token = jwt.sign({ userInfo }, "the_secret_key");
// In a production app, you'll want the secret key to be an environment variable
res.json({
token,
email: userInfo.email,
name: userInfo.name,
});
} else {
res.sendStatus(400);
}
});
// MIDDLEWARE
function verifyToken(req, res, next) {
const bearerHeader = req.headers["authorization"];
if (typeof bearerHeader !== "undefined") {
const bearer = bearerHeader.split(" ");
const bearerToken = bearer[1];
req.token = bearerToken;
next();
} else {
res.sendStatus(401);
}
}
app.listen(3000, () => {
console.log("Server started on port 3000");
});
/db/user.json
/db/events.json
// user.json
{
"name": "hasudoki",
"email": "hasudoki@gmail.com",
"password": "pass123"
}
// events.json
{
"events": [
{
"id": "1234",
"title": "Puppy Parade",
"time": "12:00",
"date": "Feb 22, 2022"
},
{
"id": "1584",
"title": "Cat Cabaret",
"time": "9:00",
"date": "March 4, 2022"
},
{
"id": "2794",
"title": "Doggy Day",
"time": "1:00",
"date": "June 12, 2022"
},
{
"id": "4619",
"title": "Feline Frenzy",
"time": "8:00",
"date": "July 28, 2022"
}
]
}
-
마지막으로
package.json
에 서버를 실행시키고, 앱을 빌드하는 코드를 넣자."scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint", "start": "node server.js & vue-cli-service serve" },
클라이언트/서버와의 관계 살펴보기
-
3개의 엔드포인트를 만들고 사용할 것이다.
/resgister
: 사용자 등록 API/login
: 사용자 로그인 API/dashboard
: 인증된 사용자만 요청이 가능한 API
-
/resgister
,/login
은response
값을token
을 반환한다. -
이떄,
vuex
관련된 작업을 한다.store
에token
값을 저장localStorage
에token
을 저장(새로고침할때 유지하기위해!)- 그리고 마지막으로
Axios Header
에token
을 추가(/dashboard
권한이 필요한 요청때문에)
-
이
token
을/dashboard
에 요청할때 포함시키면 서버에서 이token
이 인증된 토큰이 맞는지 확인 후 데이터를 반환해준다.
마무리
- 프로젝트 구조를 만들고 간단한 설명을 했다.
- 다음장부터는 사용자 등록하는 컴포넌트를 만들고 API를 이용해 등록해보자.
'개발일기 > Vue.js' 카테고리의 다른 글
[Vue.js] 토큰 기반 인증(#3. 사용자 등록) (1) | 2020.08.30 |
---|---|
[Vue.js] Vue 테스트 코드 작성하기(Jest) (0) | 2020.08.21 |
[Vue.js] 토큰 기반 인증(#1. 인증소개) (2) | 2020.07.24 |
[Vue.js] Vue 3 Reactivity (#1) (0) | 2020.07.22 |
[Vue.js] highcharts 설치 및 세팅 (0) | 2019.09.03 |