[Vue.js] 토큰 기반 인증(#2. 인증을 위한 프로젝트 구조 살피기)

하수도키

·

2020. 7. 27. 13:29

728x90
반응형
SMALL

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.jsdb 디렉토리도 만들어보자.
  • 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,/loginresponse 값을 token 을 반환한다.

  • 이떄, vuex 관련된 작업을 한다.

    • storetoken 값을 저장
    • localStoragetoken 을 저장(새로고침할때 유지하기위해!)
    • 그리고 마지막으로 Axios Headertoken 을 추가(/dashboard 권한이 필요한 요청때문에)
  • token/dashboard 에 요청할때 포함시키면 서버에서 이 token 이 인증된 토큰이 맞는지 확인 후 데이터를 반환해준다.

마무리

  • 프로젝트 구조를 만들고 간단한 설명을 했다.
  • 다음장부터는 사용자 등록하는 컴포넌트를 만들고 API를 이용해 등록해보자.
728x90
반응형
LIST