Node.js와 React로 간단한 웹페이지를 만들어보자 4편 (Node.js 마무리)

Angela·2022년 7월 6일
0

<목차>
Auth 기능 만들기
로그아웃 기능

Auth 기능 만들기

사이트의 여러 페이지 중 로그인한 사람만 이용할 수 있는 페이지 / 모두가 이용할 수 있는 페이지 등의 구분을 위해서 이 기능을 만듭니다.

  • 페이지 이동 때마다 로그인 되있는지, 안되어있는지, 관리자 계정인지 등을 체크합니다.
  • 글을 쓸 때나 지울 때 등에 권한이 있는지 같은 것도 체크합니다.

Server에서는 토큰을 DB에 저장하고, Client에서는 Cookie에 저장합니다.
페이지를 이동할 때마다 이 두 가지의 토큰이 서로 맞는지 확인 작업을 거치면서 이동할 수 있는 페이지가 맞는지 권한을 체크합니다.

이 두 토큰의 확인작업은 이러한 절차를 거칩니다.

  1. Client의 Cookie에 있는 토큰을 Server에 전달합니다.
  2. Cookie의 토큰은 현재 encoded 상태입니다. (token = user._id + 'secretToken') 이를 decode하면 온전한 user._id를 얻을 수 있습니다.
  3. decode하여 얻은 user._id를 이용해 Server의 DB에서 검색하여 이에 맞는 DB 내의 토큰을 찾아냅니다.

먼저 Auth Route부터 적어보겠습니다.
여기에는 다른 코드들과는 다르게 미들웨어가 존재합니다.
'/api/users/auth'와 (req, res)에 있는 auth가 바로 그것입니다.
미들웨어의 의미는 /api/users/auth라는 엔드포인트에서 리퀘스트를 받은 다음에 뒤의 콜백 펑션을 하기 전에 중간에서 무엇을 해준다는 것입니다.

app.get('/api/users/auth', auth , (req, res) => {})

중간에서 무엇을 해주는지는 따로 js파일을 만들겁니다.
루트 디렉토리에 middleware라는 폴더를 만들고 그 안에 auth.js 파일을 만듭니다.

let auth = (req ,res, next) => {
    //여기에 두 토큰을 비교하는 인증처리 코드를 적는다.
}

module.exports = { auth }; //이 파일을 다른 데에 자유롭게 사용하기 위해

그리고 index.js에 아래의 코드도 추가해줍니다.

const { auth } = require("./middleware/auth");

본격적으로 위의 코드들의 내용을 채워보기로 합니다.

아래는 index.js에 있는 코드입니다.
아래의 app.get() 함수에 도달했다는 것은 auth.js라는 미들웨어를 통과해왔다는 뜻이며, Authentication이 true라는 말과 같습니다.
또한 _id: req.user._id 라는 문장은 auth.js에서 req.user = user; 선언을 했기 때문에 사용 가능한 문장입니다.
isAdmin: req.user.role === 0 ? false : true 문장은 role이 0이면 일반 유저, 0이 아니면 관리자로 설정한 것임을 보여줍니다.
그 외에도 유저 스키마에 있던 항목들을 차례차례 넣어줍니다.

app.get('/api/users/auth', auth , (req, res) =>{
  
  res.status(200).json({
    _id: req.user._id, 
    isAdmin: req.user.role === 0 ? false : true, 
    isAuth : true,
    email: req.user.email,
    name: req.user.name,
    lastname: req.user.lastname,
    role: req.user.role,
    image: req.user.image
  })
})

그러면 우리는 미들웨어인 auth.js의 코드를 보도록 하겠습니다.

아래는 auth.js 파일 전체의 코드입니다.
여기서는 클라이언트의 쿠키 내 토큰과 서버의 DB 내 토큰을 비교하는 작업을 하는 코드들을 적습니다.

const { User } = require("../models/User"); //유저모델 가져오기

let auth = (req ,res, next) => {

    //클라이언트 쿠키에서 토큰을 가져옵니다.
    let token = req.cookies.x_auth;

    //토큰을 복호화 한 후 유저를 찾는다.
    User.findByToken(token, (err, user) => {
        if(err) throw err;
        if(!user) return res.json({ isAuth: false, error: true })

        req.token = token;
        req.user = user;
        next(); //미들웨어에서 탈출해 나머지를 진행할 수 있게함.

    })

    //유저가 있으면 인증 Okay
    //유저가 없으면 인증 No

}

module.exports = { auth };

User.js의 함수 정의 부분의 코드입니다.
auth.js에서 사용된 함수를 여기에서 정의해줍니다.

userSchema.statics.findByToken = function(token, cb) {
    var user = this;
    // user._id +'secretToken' = token
    // 토큰을 decode 한다. (복호화)
    jwt.verify(token, 'secretToken', function(err, decoded) {
        //유저 아이디를 이용해서 유저를 찾은 다음에
        //클라이언트에서 가져온 token과 DB에 보관된 토큰이 일치하는지 확인한다.
        user.findOne({ "_id": decoded, "token": token }, function (err, user){
            if(err) return cb(err);
            cb(null, user)
        })
    })
}

이것으로 auth설정은 모두 완료하였습니다.

로그아웃 기능

여기서부터는 로그아웃 route를 만들건데, 이는 로그아웃하려는 유저를 DB에서 찾아서 그 유저의 토큰을 지워주는 과정입니다.
토큰이 없으면 인증이 안되어서 로그인 기능이 풀리므로, 로그아웃은 해당 토큰을 지우기만 하면 구현되는 것입니다.

아래는 index.js에 있는 코드입니다.
유저를 찾을 때엔 id로 찾기 때문에 id를 사용하고, 토큰을 지웁니다.
callback func.은 에러 발생 시의 루트입니다.

//로그아웃 route
app.get('/api/users/logout', auth, (req, res) => {
  User.findOneAndUpdate({ _id: req.user._id },
    { token: "" }
    , (err, user) => {
      if(err) return res.json({ success: false, err });
      return res.status(200).send({ //no err
        success: true
      })
    })
})

아래는 로그인과 로그아웃을 Postman으로 해보는 과정입니다.
먼저 로그인 입니다. DB 내에 저장된 이메일과 패스워드를 사용했기 때문에 성공적으로 로그인하였습니다.

이제는 로그아웃 과정입니다.
로그인 과정에서 만든 토큰을 삭제하는 것인데요.
로그인과 다르게 입력은 따로 필요없기에 바로 해보았습니다.
결과는 잘 로그아웃 된 것으로 나왔습니다.

로그인의 경우 app.post를 사용했기 때문에 POST, 로그아웃의 경우 app.get을 사용했기 때문에 GET을 선택해서 SEND하는 것을 잊지 말아야 합니다.

이것으로 Node.js 위주의 백엔드 설정은 모두 끝이 났습니다.
다음부터는 React.js를 사용해 프론트엔드를 구축해보려 합니다.

0개의 댓글