msdou45 2022. 12. 20. 23:04

__________________________________________________

 

1-15  사용자 인증 미들웨어 구현하기

 

=>  < 2.3. 미들 웨어 05 >

 

 

 

— 계속해서 프로젝트는 shop_project_middleware —

폴더 : kimminsoo -> sparta -> node_js -> learning -> second_step -> shop_project_middleware

 

 

 

 

 

 

 

1-15장에서 가장 핵심적인 기능.

 

 

지금 구현된 프론트엔드는 로그인이 성공했을때 받아온 토큰을 HTTP header에 아래와 같이 넣어서 보내고 있어.

=> Authorization: Bearer < JWT토큰내용 >

 

위와 같은 양식으로 보내는 이유는 HTTP 인증 유형중, Bearer 타입을 사용하여 토큰을 전달하기 위함.

 

"Authorization" 헤더로 전달받는 토큰이 유효한지 검사하고, 만약 유효하다면 토큰 안에 있는 userId 데이터로 

해당 사용자가 데이터베이스에 실제로 존재하는지 체크하면 클리어.

 

 

***

일반적인 HTTP 인증 프레임워크는 여러 인증 스킴에 의해 사용된다. 스킴은 보안 강도와 클라이언트 또는 서버 소프트웨어에서

사용 가능성에 따라 달라질 수 있어.

 

가장 일반적인 스킴은 Basic 스킴. 그 외에도 여러 가지 있는데, 그 중 하나가 Bearer 타입의 스킴.

 

실제로 썬더 클라이언트에서도, request 쪽 Auth 카테고리를 확인하 수 있어.

해당 카테고리는 서버에 모종의 인증을 하기 위해서 그 값들을 설정할 수 있는 영역. 세부 카테고리 중에는 

대표적으로 많이 사용하는 Bearer 방식의 토큰을 서버로 전달할 수 있는 탭도 있어.

 

참고로, 구글이나 카카오 로그인을 할 때 많이 사용하게 되는 건 OAuth 2 라는 세부 탭.

***

 

 

어쨌든, 프론트엔드에서 로그인 후 받아 온 토큰을 HTTP header(정확히는 Authorization header) 에

Bearer 타입으로 토큰을 담아서 req 에 보내고 있기 때문에, 서버 측에서도 Bearer 형태로 토큰을 검증해야 해.

 

  1. Authorization 헤더로 전달받는 토큰이 유효한지 검사한다.
  2. 유효하다면, 토큰 안에 있는 userId 데이터로 해당 사용자가 데이터베이스에 실제로 존재하는지 체크

 

 

 

 

— JWT + Bearer 인증 유형에 대한 T.M.I. —

 

지금처럼 발급한 JWT 토큰은 OAuth 2.0 인증으로 발급한 액세스 토큰이 아니기 때문에 공식적으로 이 방법은 "비표준" 방식으로 볼 수 있어.

그렇지만 토큰을 헤더로 교환 할 목적으로 사용할 인증 유형이 Bearer가 제일 적절하다는 점에서 많이 사용되는 방식. 

 

참고 사이트 : https://velog.io/@city7310/%EB%B0%B1%EC%97%94%EB%93%9C%EA%B0%80-%EC%9D%B4%EC%A0%95%EB%8F%84%EB%8A%94-%ED%95%B4%EC%A4%98%EC%95%BC-%ED%95%A8-5.-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-%EA%B2%B0%EC%A0%95

 

 

 

 

 

___________________________________

 

— 사용자 인증 미들웨어 만들기 —

 

 

폴더 : kimminsoo -> sparta -> node_js -> learning -> second_step -> shop_project_middleware

파일 : middleware -> auth-middleware.js

 

 

——

< auth-middleware.js >

 

 

// schema 모델

const User = require("../models/user.js")

// jwt

const jwt = require("jsonwebtoken");

const { json } = require("express");

 

 

module.exports = async (req, res, next) => {

    const {authorization} = req.headers;    

        /*

        Bearer eyff89fsdf9... 막 이렇게 생긴토큰.

        localhost:8080/api/auth (로그인 API) 에 접속했을 때 로그인 하면서 jwt 토큰을 받아갔었어.

        프론트에서는 그 jwt 토큰을 가지고 있다가 req 를 보낼 때 HTTP header 에 

        Authorization: Bearer 타입으로 담아서 보낸거야.

        */

    const [authType, authToken] = authorization.split(" ");      

        /*

        Bearer 과 뒷 부분의 토큰을 분리해서 배열로. 

        그리고 나서 [0]의 Bearer 라는 타입과 [1] 의 jwt 토큰 내용을 배열 구조분해 할당.

        */

 

    // 헤더의 요소 중 하나인 authorization 에 담긴 토큰의 타입이 Bearer 가 아니거나, 토큰이 비어있을 경우.

    if (authType !== "Bearer" || !authToken) {      

        return res.status(400).json({errorMessage: "로그인 후 사용이 가능한 API 입니다."})

    }

 

    // 위의 if 를 넘겼다면, 무사히 유저의 req.header 에 jwt 토큰이 담겨져 왔다는 뜻. 그러니 복호화 및 검증을 해야.

    try {

        const {userId} = jwt.verify(authToken, "sparta-secret-key") // 무사히 검증이 됐다면 payload를 반환.

        const user = await User.findById(userId);

        res.locals.user = user;  

            // res 의 locals 이라는 영역의 user 정보에다가 유저의 레코드를 넣어줄 거야.

            /* 

            res.locals의 프로퍼티들은 request의 라이프 타임 동안에만 유효하다.

            html/view 클라이언트 사이드로 변수들을 보낼 수 있으며, 그 변수들은 오로지 거기서만 사용할 수 있다.

            */

        next();

    } catch (error) {

        return res.status(400).json({errorMessage: "잘못된 토큰입니다. 로그인을 해주세요."})

    }

}

 

——

=> 

res.locals.user = user;  

            // res 의 locals 이라는 영역의 user 정보에다가 유저의 레코드를 넣어줄 거야.

            /* 

            res.locals의 프로퍼티들은 request의 라이프 타임 동안에만 유효하다.

            html/view 클라이언트 사이드로 변수들을 보낼 수 있으며, 그 변수들은 오로지 거기서만 사용할 수 있다.

            */

 

— 교재 설명 —

우리는 토큰에 담긴 userId로 해당 사용자가 실제로 존재하는지 확인했습니다. 이미 데이터베이스에서 사용자 정보를 가져온것이죠. 

이 미들웨어를 사용하는 라우터에서는 굳이 데이터베이스에서 사용자 정보를 가져오지 않게 할 수 있도록 

express가 제공하는 안전한 변수에 담아두고 언제나 꺼내서 사용할 수 있게 작성했습니다!

이렇게 담아둔 값은 정상적으로 응답 값을 보내고 나면 소멸하므로 해당 데이터가 어딘가에 남아있을 걱정의 여지를 남겨두지 않게 됩니다

 

 

 

 

****

app.locals, req.app.locals, res.locals의 차이

 

app.locals

자바스크립트 객체이고, 프로퍼티들은 애플리케이션 내의 지역 변수들이다. 

애플리케이션의 라이프 타임 동안 유효하다.

 

req.app.locals

미들웨어에서 app의 지역 변수들을 사용할 수 있게 해준다.

 

res.locals

res.locals의 프로퍼티들은 request의 라이프 타임 동안에만 유효하다.

html/view 클라이언트 사이드로 변수들을 보낼 수 있으며, 그 변수들은 오로지 거기서만 사용할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

__________________________________________________

 

1-16  내 정보 조회 API 구현하기

 

=>  < 2.3. 미들 웨어 06 >

 

 

 

폴더 : kimminsoo -> sparta -> node_js -> learning -> second_step -> shop_project_middleware

파일 : app.js

 

 

 

다시 app.js 로 돌아와서, 1-15 에서 만들었던 사용자 정보 검증 미들웨어를 사용한 후 실재로 유저의 개인 정보를 조회해 보는 마지막 단계.

 

 

——

// 경로 : localhost:8080/api/users/me         미들웨어에서 사용자의 로그인 정보를 검증한 다음, 실제 정보를 조회.

router.get("/users/me", authMiddleware, async (req, res) => {

    const user = res.locals.user;

    res.status(200).json({user});

})

——

=> auth-middleware.js 파일의 모듈에서 

——

res.locals.user = user

——

이렇게 res.locals 에 값을 담은 상태에서 최종 메소드로 넘겨줬기 때문에 값을 조회할 수 있어.

이렇게 검증된 user 정보를 클라이언트에게 보여주기만 하면 끝.

 

 

 

이로서 회원가입, 로그인, 유저 정보 검증, 유저 정보 조회

총 네 가지 API 를 만들어 봤어.

 

 

 

 

 

 

 

 

 

 

 

__________________________________________________

 

1-17  RDS 구매하고 MySQL 세팅하기 

 

=>  < 2.4 MySQL → Sequelize 01>

 

 

 

< 들어가기에 앞서서 사전 지식 >

——

 

< 관계형 데이터베이스(SQL)와 비관계형 데이터베이스(NoSQL)의 개념 >


그 동안 우리가 사용했던 MongoDB비관계형 데이터베이스에 해당. 

그리고 이번 수업에서 사용해 볼 MySQL라는게 바로 관계형 데이터베이스.
데이터 형식이 자유로웠던 MongoDB와 달리 관계형 데이터베이스는 "스키마" 라는 개념이 존재하는데, 

MySQL에서는 "스키마"가 MySQL 서버의 가상 개념인 "데이터베이스"와 동일해.
** 그리고 제일 언급이 많이 되는 **"테이블"**이라는 개념은 쉽게 말해서 스키마 하위의 개념이야.

 

 

 

< mongoose라는 라이브러리의 개념 > 


mongoose는 자바스크립트로 MongoDB에 데이터를 읽고 쓰기 쉽게 해주는 라이브러리 였어.
이것을 ODM(Object Document Mapper)이라고도 부르는데, 

자바스크립트의 Object와 MongoDBDocument를 서로 Mapping해주는 도구라고 볼 수 있는 거야. 

mongooseODM의 기능을 충실하게 잘 해주고 있기 때문에 우리는 MongoDB에 쉽게 데이터를 넣고 쓰고, 관리할 수 가 있었어.

 

 

 

< sequelize라는 라이브러리를 사용해 MySQL에 데이터 읽고 쓰기 >


비관계형 데이터베이스MongoDB를 이용할때는 ODM 도구중 하나인 mongoose라는 라이브러리를 사용했었어. 

관계형 데이터베이스MySQL를 이용할때는 ODM 대신 **ORM(Object Relational Mapper)**를 사용할 수 있다고.
그리고 우리는 ORM중 가장 유명한 Sequlize라는 라이브러리를 사용해볼 예정입니다.

 

——

 

 

sequelize 라는 라이브러리를 사용하기 위해선 당연히 MySQL 서버가 있어야겠지?

그러기 위해 MySql 서버를 AWS 에서 구매해 볼거야. RDS 를 이용해서 MySQL 을 구축해 보도록 하자.

=> 

mysql 을 사용하기 위해서는, 

1. 단순하게 로컬 환경에서 mysql 서버를 실행하는 것,

2. 도커 위에서 mysql 을 띄우는 것,

3. 마지막으로 AWS에서 mySql 서버를 빌려 쓰는 것.

이렇게 세 가지 방법이 대표적.

 

AWS 에서 mySQL 서버를 빌려 쓴다면, 나중에 실제로 EC2 환경에서 서비스를 배포할 때에도

별도의 환경 설정이 필요 없이 클라우드 환경에서 돌아가고 있는 mySQL 서버를 사용할 수 있어.

 

따라서 이번 장에서는 AWS의 RDS 를 빌려서 MySQL 설치 및 설정 작업을 해보도록 하자.