[TIL] 20241122 TIL : 인증, 인가, 토큰

Jaeyoung Ko·2024년 11월 22일
0

인증, 인가에 대해 알아보기

(1) 인증 Authentication

시스템에서 서비스를 이용하려는 유저가 그 유저가 제공한 정보가 실제로 일치한 인증된 신분을 가졌는지 검증하는 작업이다.



(2) 인가 Authorization

이미 인증된 사용자에 대해서 리소스에 대한 접근이나 작업에 대한 수행 권한의 검증을 하는 작업이다.


ex. 사용자는 로그인 과정을 통해 인증(Authenticated) 과정을 거친다.
인증을 거친 사용자가 게시글 작성에 대한 권한을 검증하는 것으로 인가 (Authorized)를 받는다.






(3) bcrypt

bcrypt 모듈은 입력 데이터에 대해 단뱡향 암호화를 통해 문자열로 변환시키는 방식의 암호화 모듈이다.

// 암호화와 복호화
import bcrypt from 'bcrypt';

const password = 'MyPassword'; 			// 사용자의 비밀번호
const saltRounds = 10; 				// salt를 얼마나 복잡하게 만들지 결정합니다.

// password가 salt 정도만큼 bcrypt를 통해 해싱되어 암호화
const hashed = await bcrypt.hash(password, saltRounds);

// 비교 문자열과 해싱된 문자열에 대한 복호화 비교
const result = await bcrypt.compare('MyPassword', hashed);

console.log(result); // true








(4) Token

Access Token과 Refresh Token

A. Access Token

Access Token은 인증을 완료한 유저에게 인증 용도로 발급되는 토큰이다.

앞서 cookie에 인증이 만료되는 JWT를 설정하는 것 또한 이러한 토큰 예시로 볼 수 있다.

Access Token은 Stateless한 특징을 갖기 때문에 서버가 재시작하더라도 동일하게 작동한다.

Access Token은 사용자 인증에 필요한 모든 정보를 가지고 있으므로, 강제 만료시킬 수 없이 탈취될 경우 취약점이 매우 크기 때문에 이를 고려한 개발이 필요하다.



B. Refresh Token

Refresh Token은 Access Token을 발급받기 위한 목적의 토큰으로, 사용자의 인증 정보를 검증하기 위해 서버에서 관리된다.

앞서 말했듯이, Access Token 자체를 이용하기에는 탈취당했을 시 보안의 취약점에 큰 영향을 주기 때문에,

  • 서버에서 강제로 만료시킬 수 있는 토큰이자,

  • 서버에서 사용자의 인증 상태를 제어할 수 있는

Refresh Token을 발급하는 방식을 사용한다.

// app.js
import express from 'express';
import jwt from 'jsonwebtoken';
import cookieParser from 'cookie-parser';

const app = express();
const PORT = 3000;

// secret key 정의 : access token과 refresh token
const ACCESS_TOKEN_SECRET_KEY = `iamaccesstoken`; 
const REFRESH_TOKEN_SECRET_KEY = `iamrefreshtoken`;

// 미들웨어 설정
app.use(express.json());
app.use(cookieParser());

app.get('/', (req, res) => {
  return res.status(200).send('Hello Token!');
});

// refresh 토큰 저장소
/*
	주의: 이 예시에서는 임시로 tokenStorage에서 refresh token을 관리하지만,
    이 방식은 in memory 이기 때문에 서버 종료 시 정보가 휘발된다.
    
    실제 production에서는 별도 테이블에서 refresh token의 저장 관리를 진행해야한다

*/
let tokenStorage = {};
// 토큰 발급
app.post('/tokens', (req, res) => {
  const { id } = req.body;
  const accessToken = createAccessToken(id);
  const refreshToken = createRefreshToken(id);

  // Refresh Token 서버에 저장
  tokenStorage[refreshToken] = {
    id: id, 
    ip: req.ip, 
    userAgent: req.headers['user-agent'],
  };
  // 토큰을 쿠키에 저장
  res.cookie('accessToken', accessToken); 
  res.cookie('refreshToken', refreshToken); 

  return res
    .status(200)
    .json({ message: 'Token 발급' });
});

function createAccessToken(id) {
  const accessToken = jwt.sign(
    { id: id }, 					// JWT 데이터
    ACCESS_TOKEN_SECRET_KEY, 		// Access Token의 비밀 키
    { expiresIn: '10s' }, 			
  );
  return accessToken;
}

function createRefreshToken(id) {
  const refreshToken = jwt.sign(
    { id: id }, 					// JWT 데이터
    REFRESH_TOKEN_SECRET_KEY, 		// Refresh Token의 비밀 키
    { expiresIn: '7d' }, 
  );
  return refreshToken;
}


app.listen(PORT, () => {
  console.log(PORT, 'port : server opened');
});
profile
안녕하세요, 고재영입니다. 언제나 즐겁게 살려고 노력합니다.

0개의 댓글