본문 바로가기
Web/Node.js

13. Authentication, bcrypt, JWT

by 사라리24 2024. 4. 29.
SMALL

1. Authentication(인증)

  

  • session & cookie

    쿠키
       : 클라이언트 컴퓨터에 저장되는 작은 데이터 조각
       : 서버로부터 전송되어 웹브라우저에 저장
       :  텍스트 형식으로 주로 사용자 인증, 설정, 장바구니 등에 사용

    - 세션

     : 웹서버 측에서 유지되는 상태 정보
     : 사용자에 대한 고유한 세션ID를 통해 식별
     : 서버 메모리 또는 데이터베이스에 저장 가능

 

 

2. bcrypt

- 해시 함수를 사용하여 비밀번호를 안전하게 저장하는데 사용되는 암호화 라이브러리
- 단방향 해시 함수로 한번 해시된 값을 다시 원래 값으로 역추적하는 것이 불가능
- 솔트(salt):  해시에 고유한 솔트 값을 추가하여 보안성을 높임. 같은 비밀번호를 가진 사용자가 있더라도 서로 다른 해시값을 가짐
- 작업인자(Adaptive Work Factor): 매개변수를 조정하여 해시 작업의 복잡성을 조절. 암호 분석학적으로 안전한 해시 함수를 유지하면서도 암호화 작업에 필요한 시간을 조절할 수 있게 함

 

  • 해시함수
    임의의 길이의 데이터를 받아서 고정된 길이의 고유한 값으로 변환하는 함수.
    이러한 변환된 값은 해시 값 또는 해시 코드라고 함
    ㄴ 동일한 입력에 대해 항상 동일한 해시 값을 생성
    ㄴ 항상 고정된 출력 길이를 생성

    ㄴ 해시된 값을 통해 원본 값을 복구할 수 없음

 

 

  • bycrypt 설치하기

 
       npm i bycrypt
  
 

 

  
      < bycrypt.js >

            import * as bcrypt from "bcrypt";

            const password = 'abcd1234';
            const hashed = bcrypt.hashSync(password, 10)
            //hashSync(매개변수, 솔트값) // 솔트값: 숫자가 높을 수록 속도가 느림 // 10이하 추천
            console.log(`password: ${password}, hashed: ${hashed}`);
 

            const result = bcrypt.compareSync('abcd1234',hashed);
            console.log(result);

       </ bycrypt.js  >
  
 
password: abcd1234, hashed: $2b$10$AtpdctSuxE7u7TNwi71Rz./uKFq9dABJY.lLgo5LvDdJN9h6Du0Jy
true

 

  • 문제
    controller/auth.js 에서 login()를 bcrypt를 적용하여 로그인 프로세스를 만들어보자
 
      < data > auth.js >

            let users = [
                {
                    id: '1',
                    username : "apple",
                    password: "$2b$10$AtpdctSuxE7u7TNwi71Rz./uKFq9dABJY.lLgo5LvDdJN9h6Du0Jy",
                    name: "김사과",
                    email: "apple@apple.com",
                },
   
 
       </ data >  auth.js  >
  
먼저,
password: "1111"을 
" $2b$10$AtpdctSuxE7u7TNwi71Rz./uKFq9dABJY.lLgo5LvDdJN9h6Du0Jy" 으로 변경(hashed 값)
useridusername으로 변경

 

  
      < controllar> auth.js >
 
 
            import * as authRepository from "../data/auth.js";
            import bcrypt from 'bcrypt'; //추가
 
 
            // 로그인하는 함수 //수정
            export async function login(req, res, next){
                const { username, password } = req.body;
                const user = await authRepository.login(username);
                // const bcryptPW = bcrypt.hashSync(password, 10);
                // const result = bcrypt.compareSync('abcd1234', bcryptPW);
                if(user){
                    if(bcrypt.compareSync(password, user.password)){
                    res.status(201).json(`${username} 로그인 완료`);
                    }
                    else{
                        res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
                    }
                }
                // else{
                //     res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
                // }
            }

 
       </ controllar> auth.js  >
  
 



 

 

3. JWT(JSON Web Token)

- 웹 애플리케이션과 서비스 간에 정보를 안전하게 전달하기 위한 인증 및 권한 매커니즘을 구현하는데
   사용하는 표준화된 방법 중 하나
-  인증 및 정보 교환을 위한 토큰 기반의 인증 방식 중 하나
- JSON 포멧을 사용하여 정보 표현, 서명 및 암호화를 통해 정보의 무결성 보장
- Base 64로 인코딩된 JSON 객체이며 사용자 정보 및 기타 데이터를 안전하게 전송하기 위해 사용
-  header: JWT의 유형과 해당 알고리즘이 포함

 

  • { Header | Payload | Signature }
    - Header: 토큰 유형 및 서명 알고리즘과 같은 메타데이터가 포함
    - Payload: 토큰에 포함될 데이터가 들어있는 부분​
    - Signature: 헤더, 페이로드 및 비밀키를 사용하여 생성된 서명으로 토큰의 무결성을 검증하는데 사용

  • JSON Web Token(JWT)  설치
 
 
      npm i jsonwebtoken 
  
 

 

  • JSON Web Token(JWT) _ 토큰을 생성하고 유효성을 확인

jwt.js 생성

 

 
      < jwt.js >

            import jwt from 'jsonwebtoken';

            const secret='abcdefg1234%^&*';
            const token = jwt.sign(
                {
                    id:'apple',
                    isAdmin:false
                },
                secret,
                {expiresIn: "1h"// 얼마만큼 토근이 유지될 것인가
            );

            //expiresIn: "1h"
            //expiresIn: 2 유지되다 에러

            setTimeout(()=>{
                jwt.verify(token,secret,(error,decoded)=>{
                    console.log(error,decoded);
                });
            }, 3000); // 3초마다 찍어주기

            console.log(token);

       </jwt.js >
  
{expiresIn: "1h"} 결과

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFwcGxlIiwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTcxNDQ0NzkyMywiZXhwIjoxNzE0NDUxNTIzfQ.C_7E0JO2LEqIEEdUi9YfMa0BgPod7xJcCPvZBUShWeo
null { id: 'apple', isAdmin: false, iat: 1714447923, exp: 1714451523 }


{expiresIn: 2} 결과


 

  • Header: JWT의 유형과 해싱 알고리즘이 포함
    {
        "alg" : "HS256",
        "typ" : "JWT"
    }

 

  • Payload: 토큰에 담긴 정보가 포함
{   
     "alg" : "HS256",
     "typ" : "JWT"
}
  
    {
        id:'apple',
        isAdmin:false
    },
  

 

  • Signatur: 해더와 페이포드를 인코딩하고 비밀키를 사용하여 서명되 문자열. 서명은 토큰이 변조되지 않았음을 확인하는데 사용
  • Sign()
  
     
        jsonwebtoken.sign(payload, secretOrPrivatekey, [option, callback])
  
 
payload: JWT에 포함될 페이로드 데이터
secretOrPrivatkey: JWT 서명하기 위해 사용될 비밀 키 또는 개인 키 

 

  • 문제
    jwt.js를 참고하여 controller/auth.js에 토큰을 발행하고 login() 에 로그인이 완료되면
    클라이언트에 토근을 출력하는 프로세스를 만들어보자
  
      < controller > auth.js >

            import * as authRepository from "../data/auth.js";
            import bcrypt from 'bcrypt';
            import jsonwebtoken from 'jsonwebtoken' ; //추가

            const secret = "abcd1234%^&*" //추가

            //jwt 토근 //추가
            async function makeToken(id){
                const token = jwt.sign({
                    id: id,
                    isAdmin: false
                }, secret, {expireIn:'1h'})
                return token;
            }

            // 회원가입 함수 //수정
            export async function signup(req, res, next){
                const { username, password, name, email } = req.body;
                const hashed = bcrypt.hashSync(password, 10); //추가
                const users = await authRepository.createUser(username, hashed, password, name, email); //hashed 추가
                if(users){
                    res.status(201).json(users);
                }
            }
           
            // 로그인하는 함수 //수정
            export async function login(req, res, next){
                const { username, password } = req.body;
                const user = await authRepository.login(username);
                // const bcryptPW = bcrypt.hashSync(password, 10);
                // const result = bcrypt.compareSync('abcd1234', bcryptPW);
                if(user){
                    if(bcrypt.compareSync(password, user.password)){
                        //res.status(201).json(`${username} 로그인 완료`); //지우기
                        res.status(201).header('Token',makeToken(username)).json(`${username} 로그인 완료`) //토큰값만들기 //추가
                    }
                    else{
                        res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
                    }
                }else{
                    res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
                }
            }

            //토큰 확인 //추가
            export async function verify(req, res, next){
                const token = req.header['Token'];
                if(token){
                    res.status(200).json(token);
                }
            }
 
       <controller > auth.js  >
  
 
  
      < router > auth.js >

            import express from 'express';
            import { body } from 'express-validator';
            import * as authController from "../controller/auth.js";
            import { validate } from "../middleware/validator.js";

            const router = express.Router();

            const validateSignup = [
                body('username').trim().isLength({ min: 3 }).withMessage('최소 3자 이상 입력'),
                body('password').trim().isLength({ min: 4 }).withMessage('최소 4자 이상 입력'),
                body('email').trim().isEmail().withMessage('이메일 형식 확인'),
                validate
            ]

            router.post('/signup', validateSignup, authController.signup);

            router.post('/login', authController.login);

            router.get('/me', authController.verify); //추가

            export default router;
 
       </ router > auth.js   >
  
 

 






 

  • git-hub에 commit 하기

 

 

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

15. 환경변수, 웹소켓  (0) 2024.05.03
14. Postman 정리, 아이디 중복체크  (0) 2024.05.02
12. Validate(데이터 검증)  (0) 2024.04.29
11. 리팩토링  (0) 2024.04.26
10. 실습: Tweet  (0) 2024.04.26