MySQL

React, MySQL 8일차 (로그인 기능 만들기)

수연 (Suyeon) 2023. 10. 16. 17:15
반응형

 

PedroTech님의 풀스택 강의 8일 차를 참고했습니다.

 

 

📌 로그인 정보를 저장할 Users 테이블 생성하기

// ./server/models/Users.js

module.exports = (sequelize, DataTypes) => {
  const Users = sequelize.define("Users", {
    username: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  });
  
  return Users;
};
Users 테이블 안에는 username(사용자 이름)password(비밀번호)를 저장할 수 있습니다.

 

 

 

📌 bcrypt 설치하기

npm install bcrypt
server 폴더 위치로 이동 후, 터미널에 위와 같이 입력하면 bcrypt가 설치됩니다.

bcrypt를 사용하는 이유: 특정 데이터를 암호화해야 할 때 유용하게 사용되기 때문에 비밀번호 암호화를 위해 활용했습니다.

 

 

 

📌 Users의 router 생성하기

// ./server/routers/Users.js

const express = require("express");
const router = express.Router();
const { Users } = require("../models");

// 암호화하기 위해 사용합니다.
const bcrypt = require("bcrypt");

// *첫 번째 POST(회원가입하기)
router.post("/", async (req, res) => {
  const { username, password } = req.body;

  // 비밀번호 암호화를 해줍니다.
  bcrypt.hash(password, 10).then((hash) => {
    Users.create({
      username: username,
      password: hash,
    });
    res.json("SUCCESS");
  });
});

// *두 번째 POST(로그인하기)
router.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const user = await Users.findOne({ where: { username: username } });

  if (!user) {
    res.json({ error: "User Doesn't Exist" });
  }

  // password가 일치하는지 비교해줍니다.
  bcrypt.compare(password, user.password).then((match) => {
    if (!match) {
      res.json({ error: "Wrong Username And Password Combination" });
    }
    
    res.json("YOU LOGED IN!!");
  });
});

module.exports = router;
// install bcrypt
회원가입 코드 설명
1. req.body: 데이터(username, password)를 반환합니다.
2. bcrypt.hash(데이터, 암호화 값): 전달받은 데이터를 암호화해서 테이블에 저장될 수 있도록 해줍니다.
    (암호화 값은 커질 수록 암호화 연산이 증가하게 되어 보안을 높이는데 도움이 됩니다.)
3. Users.create(): Users라는 테이블에 값을 저장하라는 의미입니다.

로그인 코드 설명
1. Users.findOne({where: ... }): Users 테이블에서 조건(where)에 맞는 데이터 1개만 가져옵니다.
2. if (!user) {}와 if(!match): 조건과 맞는 데이터가 없을 때 실행되는 조건문입니다.
3. bcrypt.compare(데이터1, 데이터2): 매개변수들을 비교해서 성공적으로 되면 then을 실행시킵니다.
    (데이터1: 사용자가 입력한 값, 데이터2: Users 테이블에서 가져온 데이터)

 

 

 

📌 React에서 사용할 수 있도록 Users router 등록하기

// ./server/index.js

const usersRouter = require("./routes/Users");
app.use("/auth", usersRouter);
Users의 router를 사용하고 싶을 땐 http://localhost:0000/auth를 이용해야 합니다.

 

 

 

📌 회원가입 화면 만들기

import React from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
import axios from "axios";

function Registration() {
  const initialValues = {
    username: "",
    password: "",
  };

  const validationSchema = Yup.object().shape({
    username: Yup.string().min(3).max(15).required(),
    password: Yup.string().min(4).max(20).required(),
  });

  const onSubmit = (data) => {
    axios.post("http://localhost:3001/auth", data).then(() => {
      console.log(data);
    });
  };

  return (
    <div>
      <Formik
        initialValues={initialValues}
        onSubmit={onSubmit}
        validationSchema={validationSchema}
      >
        <Form>
          <label htmlFor="inputUsername">Username: </label>
          <ErrorMessage name="username" component="span" />
          <Field
            autoComplete="off"
            id="inputUsername"
            name="username"
            placeholder="(Ex. User12...)"
          />

          <label htmlFor="inputPassword">Password: </label>
          <ErrorMessage name="password" component="span" />
          <Field
            autoComplete="off"
            type="password"
            id="inputPassword"
            name="password"
            placeholder="Your Password"
          />

          <button type="submit">
            Register
          </button>
        </Form>
      </Formik>
    </div>
  );
}

export default Registration;
(Formik와 각종 함수들의 내용은 React, MySQL 풀스택 4일 차를 참고해 주시기 바랍니다.)

함수 코드 설명

1. onSubmit(): axios를 활용해서 Users 테이블로 데이터를 보내줍니다.

화면 구성 코드 설명
1. Field의 type: input 태그와 동일한 의미를 가지고 있습니다.

 

회원가입 화면입니다.

 

 

📌 로그인 화면 만들기

import React, { useState } from "react";
import axios from "axios";

function Login() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const login = () => {
    const data = { username: username, password: password };
    axios.post("http://localhost:3001/auth/login", data).then((response) => {
      console.log(response.data);
    });
  };

  return (
    <div>
      <label htmlFor="inputUsername">Username: </label>
      <input
        type="text"
        id="inputUsername"
        onChange={(e) => setUsername(e.target.value)}
      />

      <label htmlFor="inputPassword">Password: </label>
      <input
        type="password"
        id="inputPassword"
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="button" onClick={login}>
        Login
      </button>
    </div>
  );
}

export default Login;
함수 설명
1. login(): 로그인 정보를 지정된 경로로 전달한 뒤, 로그인을 성공했는지 아닌지를 확인합니다.
2. setUsername(): 사용자 이름을 저장하는 함수입니다.
3. setPassword(): 비밀번호를 저장하는 함수입니다.

화면 구성 코드 설명
1. input태그의 onChange(): 사용자가 값을 입력할 때마다 해당 값을 지정된 변수에 저장합니다.

 

로그인 화면입니다.

 

 

 

📌 App.js에 회원가입, 로그인 경로 정의하기

import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import Login from "./pages/Login";
import Registration from "./pages/Registration";

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <div className="nav">
          ...
          <Link to="/login" className="link">
            Login
          </Link>
          <Link to="/registration" className="link">
            Registration
          </Link>
        </div>

        <Routes>
          ...
          <Route path="/login" exact element={<Login />} />
          <Route path="/registration" exact element={<Registration />} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;
React에서 성공적으로 경로를 이동하기 위해 react-router-dom을 활용해서 Login과 Registration을 정의해줍니다.

 

 

 

📌 결과

1. 회원가입

회원가입을 하는 화면입니다.

 

회원가입 했을 때 입력한 값입니다.

 

비밀번호가 암호화되어 저장된 Users 테이블 데이터입니다.

 

 

2. 로그인

로그인을 성공적으로 했을 때 화면입니다.

 

로그인을 실패했을 때 화면입니다.

 

 

 

📌 느낀 점

회원가입을 하고 나서 비밀번호를 암호화하는 과정을 처음 해봤습니다. 보안을 위해 bcrypt라는 기능을 사용한다는 걸 알게 된 후 찾아보니 여러 방법들로 암호화를 할 수 있더라고요!

나중에 회원가입 기능을 구현해야 할 때 상황에 맞게 적절한 것으로 사용해야겠다는 생각이 들었습니다.

오늘 한 것들은 대부분 전에 했던 것과 비슷한 부분이 많아서 중복되는 설명은 링크로 전달해 봤습니다.

다음에는 로그인 정보가 있는 사람만 글을 쓸 수 있도록 하는 기능도 만들고 싶네요!

 

 

 

참고 사이트: [NODE] 📚 bcrypt 모듈 암호화 원리 & 사용법

728x90