본문 바로가기
programming language/Node.js

React 로그인 API _ 2 (서버만)

by cariño 2022. 11. 6.
728x90
반응형

로그인 기능을 떠나서 에러처리가 굉장히 어렵구나. 

디들웨어를 만든 부분을 다시금 정리해보기로 했다. 

 

먼저 서버부분을 확인!

 

[사용자 인증 라이브러리]

//authutill.js

const jwt = require("jsonwebtoken");
const secretKey = 'marking-access-secret-key'

const getToken = (payload, isUnLimit) => {
    const expiresIn = isUnLimit ? 60 * 60 * 24 * 365 * 100 : 60 * 60 * 24
    const token = jwt.sign(payload, secretKey, { expiresIn })
    return token
}

const verify = (token) => {
    try {
        const decoded = jwt.verify(token, secretKey)
        return decoded
    } catch (error) {
        throw new Error('VERIFY_FAIL')
    }
}

module.exports = { getToken, verify }

 

1. getToken

authutill부분도 수정이 이루어졌다. 

로그인화면에서 로그인 유지 기능을 만들고 싶었다. 그런데.. 

localStorage에 있는 토큰의 유효성이 계속 에러가 나길래 알아본 결과..

 

jwt관련 정보는 localstorage에 계속 남아 있다.  

브라우저가 종료되어도 정보는 계속 남아 있는 상태이기 때문에.. 로그아웃 기능을 아직 만들지 않은 상태인지라

다른 아이디로 로그인 시에 에러가 발생하거나, 로그인 했던 아이디(expiresIn에서 24시간으로 설정 되어있었음) 로 다시 로그인해도 에러가 나게 되었다. 

 

그래서. 로긘을 할 경우 토큰의 수명을 설정하기로 했다. 

대신 보안상 좋지 않다고 한다. 일단..... 이 기능 먼저 끝내보고 싶기에 

 

로컬에 넣어지는 수명 자체를 100시간으로 설정했다. 

isUnlimit일때 100시간, 아닐 경우 24시간으로 만들었다. 

 

이제 남은것은 클라이언트에서 로그인 유지 버튼을 눌렀을 경우 inUnLimit를 true로 설정!

 

 

2. verify()

복호화 한 코드이다. 토큰을 받아서 해당 토큰이 playload와 일치하지 않다면 에러를 던저주도록 try/catch로 설정했다. 

 

 

 

[미들웨어]

//verifyAuth.js

const { User } = require('../models/users');
const { verify } = require('../util/authutil');

const verifyA = (req, res, next) => {
    try {
        const token = req.headers.authorization
        console.log('req.headers.authorization: ', req.headers.authorization);
        
        // if (token == null) return res.sendStatus(401) // 401 Unauthorized 오류는 유효한 사용자 ID 및 암호로 처음 로그인 할 때까지 액세스하려는 페이지를로드 할 수 없음을 의미
        //로긘한 회원만 가능하게


        // 2. 복호화함 => payload가 나와
        if (token) { //토큰이 있을 경우 토큰 복호화
            const splited = token.split(' ')[1]
            const verifyToken = verify(splited)
            // console.log(verifyToken)
            // req가 서로 공유됨 다른 함수에서 똑같이 req를 쓰니까 여기서 넣은 req data를 쓸 수 있다. 
            req.user = verifyToken
        }
        next()
    } catch (error) {
        console.log('error :::::::::::::::: ', error);
        res.status(403).send({ systemMessage: "VERIFY_FAIL" })
    }

}

module.exports = { verifyA };

 

1. 먼저, 주석처리된 부분 중

`// if (token == null) return res.sendStatus(401) // 401 Unauthorized`

 

 

app.js에서 미들웨어를 글로벌로 추가해놨다. 

 

미들웨어를 하나로 다 하게 되면 모든 통신에서 작동하기 때문에 비 로그인시에도 적용이 된다. 

그래서 미들웨어를 총 2가지로 나눌까? 하다가 일단 만드는 웹페이지가 로그인을 해야지만 볼 수 있는 화면으로 만들어 놨기 때문에 나는 authorization은 한개로 하기로 했다. 

 

결국 위 주석로직은 필요없게되는 것이다. 

이미 로그인 된 사용자(토큰을 보유)가 토큰을 검증하는 것이기때문에 

토큰이 없다는 상황의 if문이 필요 없었던 것이다. 

 

 

2. 복호화 부분

토큰의 bearer부분은 지워주고 기존 토큰만 보내줘야 한다. 

그래서 splited된 토큰을 따로 변수로 넣었다. 

 

그리고 제일 햇갈렸던 req.user부분....

`req.user = verifyToken`

 

* 미들웨어에서 사용하는 req는 결국 global로 쓰이게 된다. 

즉 req가 자체가 공유되기 때문에, verifyToken을 req data에 넣을 수 있다. 

 

결국은 복화한 데이터를 따로 스키마의 User를 가져와서 인증된 토큰에 대한 데이터를 넣어주는 것이 아니라, 

저자체로 이미 복호화한 데이터가 들어간 것이 된다. 

 

 

3. 에러일시 한번에 처리

기존엔 로직 내 else부분은 거의 에러를 추가해서 넣었었는데

catch하나로 인증 실패시 상태값send해줬다. 

 

 

[토큰 검증 router]

// 토큰검증용
router.post('/comfirm-token', function (req, res, next) {
    // 응답받은 req.body를 가져옴
    const { token } = req.body

    try {
        const verifyToken = verify(token) //사용자 정보가 들어감
        if (!verifyToken) throw new Error('unauthorized')
        res.json({ userId: verifyToken.email, name: verifyToken.name })

    } catch (error) {
        res.status(401).send('unauthorized')

    }
})

 

위에서 만들었던 인증 기능에 대한 정보를 클라이언트에 보내줘야한다. 

만약에 verify에서도 토큰이 일치하지 않다면 catch(error)로 가게 된다. 

 

하고 나서 보니 간단한거 같은데...... 진빠지고 힘들어서 2틀간은 컴퓨터를 열어보지 못했다. 

로그인 검증 쪽 후유증이 좀 있으니 많이 공부하시고 도전하시길...

728x90

'programming language > Node.js' 카테고리의 다른 글

NestJS  (0) 2023.06.25
AWS_S3 client 배포하기  (1) 2022.12.01
express 사용해 보자!  (0) 2022.10.24
Webpack  (0) 2022.09.20
모듈 시스템  (1) 2022.09.20

댓글