본문 바로가기
Node.jstesttset

[Node] JWT , Login 인증

by 리슨업 2024. 1. 16.
[ Node ] JWT , Login 인증

 

 

 

 

# JSON WEB TOKEN

JWT는 JSON형태로 web Token을 주고 받는 걸 말한다. 

주로 권한을 확인하거나 로그인 시 token을 발급할 때 주로 사용되는데, 로그인 시에 해당 사용자가 DATABASE나 JSON 파일 등에 존재여부 로직으로 검증 한 후에 Token을 발급하여 클라이언트 서버에 response 하여 저장하는 형식으로 많이 사용된다. 

 

인증의 기본적인 로직은 아래와 같다.

 

 

 

1. CLIENTSERVER에 로그인 request

2. SERVER는 엔드포인트 기준으로 정의된 verify 로직을 수행하는데 여기서 요청받은 payload를 DATABASE에 고객정보를 sql문으로 요청한다.

3. DATABASE는 고객정보가 존재하면 해당 user data를 return, 없다면 null 값을 리턴한다.

4. Node.js 서버는 null이면 토큰을 미발급 , 고객정보가 있다면 토큰을 생성한다.

5. 발급한 토큰을 CLIENT에 전달한다.

 

클라이언트는 발급 받은 토큰으로 권한을 부여받게 되고, 토큰의 유무에 따라 페이지 진입 등이 가능해진다.

 

 

 

# JWT 발급조건

JWT은 발급하려면 해당 조건이 필요하다.

 

1) header : 알고리즘 ,Type 

{
  "alg": "HS256",
  "typ": "JWT"
}

 

JWT 발근에 필요한 header 알고리즘과, 타입을 명시해야 하고, "HS256" , "JWT"는 기본 값으로 주어지는 알고리즘과 타입이다. 

"alg"는 사용할 서명 알고리즘을 말하며, "typ"는 토큰의 타입을 명시한다.

 

 

2) payload

JWT는 header의 알고리즘과 타입을 기반으로 전달받은 payload를 인코딩 한다.

 

 

3) signature  : 시크릿 키

해당 payload를 SHA-256 방식으로 인코딩만 하면 보안상 당연하게 문제가 된다. 이것을 검증, 서명하는 방식으로 시크릿키를 사용한다. 

require('dotenv').config();

 

보안을 위하여 위와 같이 .env파일로 시크릿키를 관리한다. 

 

 

 

# JSON WEB TOKEN  생성

Node.js에서는 'jsonwebtoken' 라이브 러리를 이용하여 sign 메서드를 이용하여 토큰을 생성한다. 

 

1)  jsonwebtoken require 

const jwt = require('jsonwebtoken'); //jsonwebtoken 라이브러리

 

 

2) sign 메소드

위 단락의 변수를 통해서  jwt.sign()으로 JWT를 생성이 가능하다.

 

`jwt.sign(payload, secretOrPrivateKey , [options, callback])` 

 

const createToken = (id)=>{
    return jwt.sign({ id: id }, process.env.JWT_SECRET, 
    {
        expiresIn: '1h' // 토큰 유효시간 설정
    });
}

 

sign 메소드는 주어진 페이로드와 시크릿 키, 그리고 선택적 옵션을 이용하여 JWT를 동기적으로 생성한다.

예를 들어, `createToken` 함수는 고객 정보의 `id`를 매개변수로 받아 JWT를 생성하는데
 이 토큰은 주어진 `id`를 페이로드로 포함하고, 환경 변수 `process.env.JWT_SECRET`에 저장된 시크릿키를 사용하여 서명된다. 토큰의 `expiresIn` 옵션은 토큰이 1시간 후에 만료되도록 설정된다.

토큰 내에는 `id` 정보가 포함되어 있지만, 시크릿키 자체는 포함되지 않는다.
시크릿키는 서버에 은닉된 채로 남아 있어야 하며, 토큰의 무결성과 인증을 위한 서명 생성에 사용되는 key이다.

서명은 토큰의 마지막 부분인 해시 값으로 생성되며, 이 해시는 토큰이 유효한지 검증할 때 사용된다.
검증 과정에서 "서버는 저장된 시크릿키를 사용하여 토큰의 해시 값을 다시 계산하고, 이것이 토큰에 포함된 서명의 해시 값과 일치하는지 비교한다."


일치한다면, 이는 토큰이 해당 서버에서 발급되었으며 변조되지 않았음을 의미한다.

 

 

 

 

# JWT  localStorage 저장

토큰이 발급 된 이후에 권한이 부여된 요청을 진행하게 되면 저장 된 토큰을 header에 포함시켜 서버에 요청하여야 한다.

이게 가능하려면 Client에 해당 토큰값을 가지고 있어야 가능한데 저장방법으로 세션, 쿠키, 로컬 스토리지 등 여러방법이 유효하지만 LocalStorage이 가장 간편한듯하여 애용하고 있다. 

 

다만, 로컬에 토큰 값을 저장하면 보안에 문제가 이를 사용하려면 토큰 만료시간되거나 로그아웃 시에 로컬스토리지에 있는 token값을 명확하게 삭제를 해주는 로직을 추가하여 보안성에 유의를 두어야 한다.

 try{
        const response = await fetch('엔드포인트', {
                method : "POST",
                headers : {
                    'ConTent-Type' : 'application/json'
                },
                body : JSON.stringify({
                    user_id : loginData.id.value,
                    user_password : loginData.pw.value
                })
            });
    
            if(!response.ok){
                throw new Error('서버 응답 오류: ' + response.status);
            }
            
            const resultData = await response.json();      
            localStorage.setItem('token', resultData.token); // 토큰 저장
        }
        catch(error){
            console.error(error);
    }

 

위 예제처럼 일반적으로 response 된 token 값을 저장하여 사용한다. 

이후 페이지 이동이나, 권한 재 확인 시에는 클라이언트에서 Bearer 스키마 값을 포함하여 'Authorization' : 'Bearer + token' 값을 보내어 이를 verify 하면 된다.

 

 

[ Client ]

    if (token) {
        try {
            await fetch('엔드포인트', {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${token}` // 토튼 값 header로 전달 
                }
            });
        } catch (error) {
            console.error(error);
        }
    }

 

 

[ Back End ]

    try{
        jwt.verify(token , process.env.JWT_SECRET); // hash값 비교
        next();// 오류가 없으면 다음 로직 수행 
    }
    catch(error){
        return res.json({ Auth : false ,  message : '만료된 토큰이거나 서버오류' });
    }

 

요청받은 req.headers.authorization 을 가지고 토큰과 시크릿 키의 hash값을 비교하여 서버에서 발급한 토큰이 맞는지 검증요청 하면 된다. 

 

 

 

 

'Node.jstesttset' 카테고리의 다른 글

[Node] - bcrypt  (1) 2024.01.14
Node.js 미들웨어란?  (0) 2023.11.27
Node.js 동기/ 비동기 에러처리  (1) 2023.11.23