City At Night

[MernStack] Blog 만들기 7. Routing-user기능 // 코드수정필요(미완성) 본문

MernStack

[MernStack] Blog 만들기 7. Routing-user기능 // 코드수정필요(미완성)

Wuny 2021. 3. 22. 01:06
728x90
반응형

user router를 만들어보겠다.

우선 회원가입기능을 만들고 회원가입을 하고나서 회원가입이 잘 되었느지 확인하는 회원검색 기능까지 추가로 만들겠다.

먼저, 회원가입은 보안을 신경써야한다. 
회원가입시 입력한 비밀번호가 해킹 당해버리면 개인정보가 유출되기 때문에 보안적인 요소를 먼저 설명하겠다.


 JWT(Javascript Web Token) 방식

1. 서버로부터 인증된 클라이언트는 서버로 부터 토큰값을 받게 된다.
2. 유저는 글을 작성하거나 사용자를 검색할때 서버에게 요청을 보내는 동시에 토큰값도 같이 보낸다.
3.  위 1번에서 서버가 클라이언트에게 보낸 토큰값과 2번에서 클라이언트가 서버로 보낸 토큰 값이 일치하면,, 클라이언트 요청에       응답한다.
4. 토큰값의 유효시간은 개발자 마음이다.(만약 1시간으로 했다면.. 사용자는 1시간 단위로 재인증을 해야한다)

JWT 만들어지는 과정

1. 사용자가 패스워드 입력
2. 패스워드에  Salt라는 보안요소 추가 ( 원래 음식에 소금을 뿌리게 되면 음식+소금이 되는 느낌)
3. 해쉬 알고리즘 적용


 

1. 보안요소 다운로드

$> npm i bcryptjs jsonwebtoken

bcryptjs와 jsonwebtoken을 설치해준다.

 

2.1 routes/api user.js 필요한 모듈 불러오기

import express from 'express';
import bcrypt, { hash } from 'bcryptjs';

import jwt from 'jsonwebtoken';

//Model
import User from '../../models/user'

const router = express.Router();

필수적인 express와 1번에서 설치한 bcrypt, jwt를 불러온다.
user에 관한 라우터를 만들기위해 User모델도 불러오고 
익스프레스의 라우터 기능을 router라는 변수에 초기화 시킨다.

2.2  routes/api user.js  회원가입 기능 작성

//회원가입
router.post('/', (req, res) =>{
    console.log(req)
    const {name, email, password} = req.body

    //Simple validation
    if(!name || !email || !password) {
        return res.status(400).json({msg : "모든 필드를 채워주세요."})
    }
})

user모델을 보면 name, email, password 속성은 required이므로 3가지는 필수적으로 적는다.
위 3개의 속성을  req.body에 담아서 서버로 보낸다.

 만약 name, email, password 중 하나라도 존재하지 않으면   status error 400을 띄우고 에러 메세지를 보냅니다.

2.3  routes/api user.js  중복검색후 유저 등록

  //Chenck for exising user
    User.findOne({ email }).then((user) => {
        if (user)
          return res.status(400).json({ msg: "이미 가입된 유저가 존재합니다" });
        const newUser = new User({
          name,
          email,
          password,
         });
        }

User모델에서 내가 회원가입에 적었던 email이 있는 user를 찾는다. (중복 검색)
만약 유저가 존재한다면 400 error와 메세지를 보낸다.

그렇지 않으면( 존재하지 않으면,, 중복회원이 없다는 뜻)
내가 적었던  name, email, password를 NewUser로 초기화한다.

2.2  routes/api user.js  보안요소 추가. 

        bcrypt.genSalt(10, (err, salt) => { 
          bcrypt.hash(newUser.password, salt, (err, hash) => { //소금쳐진 패스워드에 해쉬값을 적용
            if (err) throw err; //에러가 있으면 에러를 던져 주고
            newUser.password = hash;  // 에러가 없으면 패스워드에 해싱을 적용한다.
            newUser.save().then((user) => {  // 새로운 유저를 저장하는데 
              jwt.sign(  // 그 새로운 유저를 jwt에 등록한다.(id, JWT_SECRET,expiresIn, ...등등
                { id: user.id },   //id
                JWT_SECRET,        // JWT_SECRET는 .env파일에 적용할것임
                { expiresIn: 3600 },  // 토큰의 유효시간은 3600초로 하겠다. 1y, 1d 식으로도 변경가능
                (err, token) => {
                  if (err) throw err;
                  res.json({
                    token,
                    user: {
                      id: user.id,
                      name: user.name,
                      email: user.email,
                    },
                  });
                }
              );
            });
          });
        });

 

bcrypt라이브러이의  genSalt를 사용하는데 파라미터 값으로 10이 들어가 있다.
이는 2^10만큼 돌린다는데..이건 더 자세히 알아봐야할것 같다.

위 여덟번 째 줄 JWT_SECRET을 .env파일에 등록해줘야 한다.

3. .env에 JWT_SECRET 추가

JWT_SECRET = "wuny"

JWT_SECRET위에 전 포스팅에서 몽고DB URI가 등록되어 있을것이다.
그때처럼 index.js로 연결 시켜주자


 [config/index.js]

import dotenv from "dotenv";
dotenv.config();

export default{
    MONGO_URI : process.env.MONGO_URI,
    JWT_SECRET : process.env.JWT_SECRET, //추가 됨
};

 

4. 회원가입이 잘 되었느지 확인을 위해 회원 검색 기능 추가.

 [routes/api/user.js]

//회원 검색
router.get('/', async(req, res)=> {
    try {
        const users = await User.find();
        if(!users) throw Error("No users")
        res.status(200).json(users)
    } catch(e){
        console.log(e);
        res.status(400).json({
            msg:e.message
        })
    }
});


6.  App.js에  user 라우터 추가

import userRoutes from './routes/api/user';
app.use('/api/user', userRoutes)

잊지말자!! app.js에서 모든게 실행된다.

7.  PostMan으로 회원가입 후 회원 검색 (잘 동작하는지 테스트)

포스트 요청으로 name, email, password를 적어주고 send를 눌러준다.
시부레 회원가입 요청을 서버에서 못 받고 있다.... 무한 로딩이다...

(node:15710) UnhandledPromiseRejectionWarning: ValidationError: user validation failed: role: `User` is not a valid enum value for path `role`.
    at model.Document.invalidate (/home/wuny/Documents/MyBlog/node_modules/mongoose/lib/document.js:2691:32)
    at /home/wuny/Documents/MyBlog/node_modules/mongoose/lib/document.js:2512:17
    at /home/wuny/Documents/MyBlog/node_modules/mongoose/lib/schematype.js:1241:9
    at processTicksAndRejections (internal/process/task_queues.js:79:11)
(node:15710) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:15710) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
POST /api/user/ - - ms - -

서버에선.. 이러한 에러가 뜬다.. 내일 고쳐야지..지금은 시간이 늦었으니 ㅜㅜ 
--------------------------------------------------------------------------------------

<수정>
초보같은 실수를 해버렸다.(사실 초보임)
user 모델에서 오타가 났다..

보이는가..? 
대소문자 구분을 잘해야한다.
enum값으로 user를 default값으로 설정하려고 했다.
enum의 값을 default 값으로 대소문자 구분을 잘하여 적어주자.

아무튼 다시  포스트맨에서 Send를 눌러주면 성공적으로 회원가입 정보가 보내진걸 알 수 있다.

그 다음 회원검색 기능도 만들었으니 확인해본다.

가입했던 TestName으로 정보들이 잘 들어가 있다.


오~좋은 사이트

728x90
반응형
Comments