[BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - Passport, JWT๋ฅผ ์ด์šฉํ•œ ์ธ๊ฐ€ ์ฒ˜๋ฆฌ

2022. 4. 11. 22:18ใ†Programming Project ์ž‘์—…์‹ค/๋‚ด์šฉ ์ •๋ฆฌ

728x90
๋ฐ˜์‘ํ˜•

 

Project Git Hub

 

 

๐Ÿ—‚ ๋ชฉ์ฐจ

โ— [BackEnd][Node.js][nest.js-PJ] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ์ดˆ๊ธฐ ๊ตฌ์„ฑ(Pipe, TypeORM, Configuration, Swagger, Logger)

โ— [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ํšŒ์› ๊ฐ€์ž…

โ— [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - JWT๋ฅผ ์ด์šฉํ•œ Login

โ— [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - Passport, JWT๋ฅผ ์ด์šฉํ•œ ์ธ๊ฐ€ ์ฒ˜๋ฆฌ

โ— [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - Custom Decorator

โ— [BackEnd][Node.js][nest.js-PJ] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ๊ฒŒ์‹œํŒ ๋งŒ๋“ค๊ธฐ : ์ดˆ๊ธฐ ๊ตฌ์„ฑ(Entity, Controller,Module,Repository,Service)

 

 

 

 

๐Ÿ“š ๋ถ€๋ก

โ— [Node.js] Node.js ๊ธฐ์ดˆ
โ— [JavaScript] ๊ธฐ๋ณธ ๋ฌธ๋ฒ• 
โ— [BackEnd][Node.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ์ดˆ๊ธฐ ๊ตฌ์„ฑ
โ— [BackEnd][Node.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ์ดˆ๊ธฐ ๊ตฌ์„ฑ : DB ์—ฐ๊ฒฐ
โ— [BackEnd][Node.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ์ดˆ๊ธฐ ๊ตฌ์„ฑ : DB ์—ฐ๊ฒฐ(Sequelize)

โ— [Web] URL์˜ ์ดํ•ด
โ— 
[Spring] Spring์ด๋ž€?
โ—[Node.js][Nest.js] ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ Data ํ˜•์‹ ๋ณ€ํ™˜ํ•˜๊ธฐ - Pipe
โ—[Node.js][Nest.js] Configuration (์„ค์ •)
โ—
[Node.js][Nest.js]TypeORM
โ— [Node.js][Nest.js] Logger ๊ธฐ๋Šฅ
โ—
[JavaScript] Promise์™€ async ๊ทธ๋ฆฌ๊ณ  await 
โ— 
[Nest.js] API ์„ค๊ณ„ - ์š”์ฒญ, ์‘๋‹ต ๊ฐ์ฒด (Request, Response Object) 
โ— 
[์ •๋ณด๋ณด์•ˆ] JWT(JSON Web Token) ์ด๋ž€? 
โ— 
[Nest.js] Middle Ware(๋ฏธ๋“ค์›จ์–ด)






 

 

 

 

๐Ÿค” ๋‚ด๊ฐ€ ๋งŒ๋‚œ Error

โ— [Node.js][Error] Cannot find module '.dotenv'

 

 

 

 

 

 

 

 

 

๐Ÿš€ Passport, JWT๋ฅผ ์ด์šฉํ•œ Token ์ธ์ฆ / ํšŒ์› ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ

    ๐Ÿ”ฝ  ๊ฐœ์š”

        ๐Ÿ“ฆ DevInquryReplyVO.java

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ์ฃผ๋‹ˆํ•˜๋ž‘์€ ํšŒ์›์ด Login์„ ํ•  ๋•Œ, Server์—์„œ Token์ด ๋ฐœํ–‰๋˜๋„๋ก ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

ํ•ด๋‹น ํšŒ์›์ด `Request(์š”์ฒญ)`์„ ๋ณด๋‚ผ ๋•Œ, `Request Header`์— Token์„ ๋„ฃ์–ด `Request`๋ฅผ ๋ณด๋‚ด๊ฒŒ ๋˜๋Š”๋ฐ, ์ด ์•ˆ์— `Payload`๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

`Payload` ์•ˆ์—๋Š” ํšŒ์›์˜ ID๊ฐ€ ๋“ค์–ด๊ฐ€๋„๋ก ์„ค์ •์„ ํ•ด ์คฌ๊ณ , ํ•ด๋‹น Token์ด ์œ ํšจํ•œ์ง€๋ฅผ Server์—์„œ `Secret Text`๋ฅผ ์ด์šฉํ•˜์—ฌ ์•Œ์•„๋‚ด๋ฉด `Payload` ์•ˆ์— ํšŒ์› ID๋ฅผ ์ด์šฉํ•ด์„œ Data Base์•ˆ์— ์žˆ๋Š” ํšŒ์› ID์— ํ•ด๋‹นํ•˜๋Š” ํšŒ์› ์ •๋ณด๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

์ด๋Ÿฌํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ `Passport` Module์ธ ๊ฒƒ์ด์—์š”.

 

๋™์ž‘ ๋ฐฉ์‹ ๋„ํ‘œ ์ถœ์ฒ˜ : ์ธํ”„๋Ÿฐ - ๋”ฐ๋ผํ•˜๋ฉฐ ๋ฐฐ์šฐ๋Š” NestJS

 

์ฃผ๋‹ˆํ•˜๋ž‘์€ ์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ 4๋ฒˆ๊นŒ์ง€ ์ž‘์—…์„ ์™„๋ฃŒํ•œ ๊ฒƒ์ด์—์š”.

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” Clinet๊ฐ€ `Request Header`์— Token์„ ๋„ฃ์–ด ๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด Server๊ฐ€ ๊ฒ€์ฆํ•˜๊ณ , ํ•ด๋‹น ํšŒ์›์ด Data Base์— ์žˆ๋Š”์ง€ ์ฐพ๊ณ , ์žˆ์œผ๋ฉด ํ•ด๋‹น ์ •๋ณด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋˜๊ณ , ์—†์œผ๋ฉด `Exeption`์ด ํ„ฐ์ง€๋„๋ก ํ•ด ์ค„ ๊ฒƒ์ด์—์š”.

 

 

 

 

    ๐Ÿ”ฝ  Module

        ๐Ÿ“ฆ ์„ค์น˜ํ•˜๊ธฐ

 

โ–บ ํ•„์š” Module

    โ— @ypes/passprot-jwt : passport-jwt Module์„ ์œ„ํ•œ Type ์ •์˜ Module.
       - `TypeScript`๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Type์„ ๊ณ„์† ์ •์˜ ์ค‘

 

๋ช…๋ น์–ด

npm i @types/passport-jwt --save

 

$ npm install @types/passport-jwt --save

 

 

 

 

    ๐Ÿ”ฝ  ์ดˆ๊ธฐ ๊ตฌ์„ฑ

        ๐Ÿ“ฆ jwt.strategy.ts ์ƒ์„ฑ

 

jwt.strategy.ts Path

 

 

jwt.strategy.ts import ๋ถ€๋ถ„

 

 

jwt.strategy.ts

๋ฐ˜์‘ํ˜•

์ตœ์ดˆ 24๋ฒˆ์งธ ์ค„์„ ๋ณด๋ฉด `@Injectable()`์„ ์ด์šฉํ•˜๋Š”๋ฐ, ์ด์œ ๋Š” `JwtStrategy` Class๋ฅผ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ `DI(Dependency Injection)`์„ ํ†ตํ•ด ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ธ ๊ฒƒ์ด์—์š”.

`passportStrategy` Class๋ฅผ ์ƒ์†ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ํ•ด๋‹น Class์— ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ด๊ณ , ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ `Strategy`๋ฅผ ์ „๋‹ฌํ•˜๋Š”๋ฐ, `Passport-jwt` ์ฆ‰, `JWT Strategy(์ „๋žต)`์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•จ์ธ ๊ฒƒ์ด์—์š”. ์ด๋ฆ„์€ `Strategy`์ด์ง€๋งŒ, `import` ๋ถ€๋ถ„์„ ๋ณด๋ฉด `passport-jwt`๋ฅผ ํ•ด๋‹น ์ด๋ฆ„์œผ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

์œ„์— ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๋Š” ์ด์œ ๋Š” JWT๋ฅผ ํ†ตํ•œ Login์„ ๊ตฌํ˜„ํ•  ๋•Œ, ๊ธฐ๋ณธ ์ „๋žต์„ `JWT`๋กœ ์„ค์ •ํ•ด๋†จ๋˜ ๊ฒƒ์ด์—์š”. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๋ž๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž ๋ถ€๋ถ„์„ ์‚ดํŽด ๋ณผ ๊ฒƒ์ด์—์š”.

`UserRepository`๋ฅผ `DI`ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๊ทธ ์ด์œ ๋Š” `JWT`๊ฐ€ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•œ ๋’ค `Payload`์•ˆ์— ์žˆ๋Š” ํšŒ์› ID๋ฅผ ํ†ตํ•ด Data Base์—์„œ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•จ์ธ ๊ฒƒ์ด์—์š”.

`Repository`๋ฅผ `DI`ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” `@InjectRepository`๋ฅผ ์ด์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์žŠ์œผ๋ฉด ์•ˆ๋˜๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ ๋‹ค์Œ ์ƒ์„ฑ์ž Body๋ถ€๋ถ„์— `super() - ๋ถ€๋ชจ Component(JAVA : Class)์˜ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ`๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ, ๋‘๊ฐ€์ง€ Option์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•จ์ธ ๊ฒƒ์ด์—์š”. ์ตœ์ดˆ Secret Key์— `auth.module.ts`์—์„œ๋„ ๋„ฃ์–ด ์คฌ์—ˆ๋˜ JWT ๋น„๋ฐ€ ๋‚ด์šฉ์„ ๋„ฃ๊ธฐ ์œ„ํ•จ์ธ๋ฐ, ์ฃผ๋‹ˆํ•˜๋ž‘์€ `Configuration`์„ ํ†ตํ•ด ๋งŒ๋“  `.yml`์— ์žˆ๋Š” ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์œ„์™€ ๊ฐ™์ด ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

`auth.module.ts`์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ `JWT`๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•จ์ด๊ณ , ์ด ๊ณณ์—์„œ๋Š” `JWT`๊ฐ€ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•จ์ธ ๊ฒƒ์ด์—์š”. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๊ณณ ๋ชจ๋‘ `Secret Key`๊ฐ€ ๋™์ผํ•˜๊ฒŒ ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

`JwtFromRequest`๋Š” `Client Request Header`์— `Bearer Token` Type์œผ๋กœ ์ „๋‹ฌ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š”๋ฐ, ์ด `Request Header`์— ํ•ด๋‹น ๋‚ด์šฉ์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด ํ•ด์ค€ ๊ฒƒ์ด์—์š”.

์ •๋ฆฌํ•ด๋ณด๋ฉด `JWTFromRequest`์—์„œ JWT๋ฅผ ๊ฐ€์ ธ์˜จ ๋’ค `secretOrKey`๋ฅผ ์ด์šฉํ•ด์„œ ์œ ํšจํ•œ ๊ฐ’์ธ์ง€ ๊ฒ€์ฆ์„ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์ด๋ฒˆ์—๋Š” `valide()`๋ฅผ ์‚ดํŽด๋ณผ ๊ฒƒ์ด์—์š”.

์œ„์—์„œ Token์ด ์œ ํšจํ•œ์ง€ ํ™•์ธ์ด ๋˜๋ฉด `validate()`์—์„œ `payload()`์— ์žˆ๋Š” ํšŒ์› ID๊ฐ€ Data Base์— ์žˆ๋Š” ์ •๋ณด์ธ์ง€๋ฅผ ํ™•์ธํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ํšŒ์› ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

return ๊ฐ’์€ `@UseGuards(AuthGuard())`๋ฅผ ์ด์šฉํ•œ ๋ชจ๋“  `Request Object`์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์—์š”.

 

์œ„์—์„œ ๋งŒ๋“ค์–ด ์ค€ Class๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” `Auth Module Providers`ํ•ญ๋ชฉ์— ๋„ฃ์–ด์ฃผ๊ณ , ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ `JwtStrategy`์™€ `PassportModule`๋„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— `export` Keyword๋„ ํ•จ๊ป˜ ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

        ๐Ÿ“ฆ Auth Module ๋“ฑ๋ก

 

auth.module.ts Import ๋ถ€

auth.module.ts

40๋ฒˆ์งธ ์ค„์— `JwtStrategy`๋ฅผ ์ถ”๊ฐ€ํ•ด ์คฌ๋Š”๋ฐ, ํ•ด๋‹น `Auth` Module์—์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋“ฑ๋กํ•ด ์ฃผ๋Š” ๋ถ€๋ถ„์ด๊ณ , `exports`๋ฅผ ๋งŒ๋“  ๋’ค `JwtStrategy`, `PassportModule`์„ ๋„ฃ์–ด์ฃผ์—ˆ๋Š”๋ฐ, ๋‹ค๋ฅธ Module์—์„œ๋„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋“ฑ๋กํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

ํ•˜์ง€๋งŒ, ์•„์ง `User` ๊ฐ์ฒด๊ฐ€ `Request` ์•ˆ์— ๋„ฃ์–ด์ฃผ๋Š” ์ž‘์—…์„ ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ์—์š”.

 

 

 

 

        ๐Ÿ“ฆ ํšŒ์› Object ์ •๋ณด ๊ด€๋ จ

`jwt.strategy.ts`์—์„œ `valid()`์˜ return Value๋ฅผ user Object๋กœ ์ค€ ๊ฒƒ์ด์—์š”.

๊ทธ๋ž˜์„œ `Request`์•ˆ์— user Object๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ง€๊ธˆ ์ƒํƒœ์—์„œ๋Š” `Request`๋ฅผ ๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด user Object๊ฐ€ ์—†๋Š” ๊ฒƒ์ด์—์š”.

์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด `UseGuards`๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ, ์ด ์•ˆ์— `@nestjs/passport`์—์„œ ๊ฐ€์ ธ์˜จ `AuthGuard()`๋ฅผ ์ด์šฉํ•˜์—ฌ `Request`์•ˆ์— user Object๋ฅผ ๋„ฃ์–ด ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ์ด์šฉํ•  `AuthGuard()`, `useGuards`๋Š” `Guards`๋ผ๋Š” `Middle Ware`์ธ๋ฐ, ์ด์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ `์ด ๊ณณ`์— ์ค€๋น„ ํ•ด ๋‘˜๊ฒŒ์š”.

 

 

 

    ๐Ÿ”ฝ  ๊ฒฐ๊ณผ

auth.controller.ts - test()

๋จผ์ € Test๋ฅผ ์œ„ํ•œ Route Method๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

 

        ๐Ÿ“ฆ POSTMAN

POSTMAN

Login์„ ํ•˜์—ฌ `Response(์‘๋‹ต)`์œผ๋กœ ์ „๋‹ฌ๋œ Token์„ ๊ฐ€์ง€๊ณ  ์ธ์ฆ์„ ํ•ด ๋ณผ ๊ฒƒ์ด์—์š”.

 

์š”์ฒญ์œผ๋กœ ๋“ค์–ด์˜จ ๊ฐ’์„ ํ™•์ธ ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ ๊ฐ’ :  <ref *2> IncomingMessage {
  _readableState: ReadableState {
    objectMode: false,
    highWaterMark: 16384,
    buffer: BufferList { head: null, tail: null, length: 0 },
    length: 0,
    pipes: [],
    flowing: null,
    ended: true,
    endEmitted: false,
    reading: false,
    constructed: true,
    sync: true,
    needReadable: false,
    emittedReadable: false,
    readableListening: false,
    resumeScheduled: false,
    errorEmitted: false,
    emitClose: true,
    autoDestroy: true,
    destroyed: false,
    errored: null,
    closed: false,
    closeEmitted: false,
    defaultEncoding: 'utf8',
    awaitDrainWriters: null,
    multiAwaitDrain: false,
    readingMore: true,
    dataEmitted: false,
    decoder: null,
    encoding: null,
    [Symbol(kPaused)]: null
  },
  _events: [Object: null prototype] { end: [Function: clearRequestTimeout] },
  _eventsCount: 1,
  _maxListeners: undefined,
  socket: <ref *1> Socket {
    connecting: false,
    _hadError: false,
    _parent: null,
    _host: null,
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: true,
      ended: false,
      endEmitted: false,
      reading: true,
      constructed: true,
      sync: false,
      needReadable: true,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: true,
      destroyed: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      dataEmitted: false,
      decoder: null,
      encoding: null,
      [Symbol(kPaused)]: false
    },
    _events: [Object: null prototype] {
      end: [Array],
      timeout: [Function: socketOnTimeout],
      data: [Function: bound socketOnData],
      error: [Function: socketOnError],
      close: [Array],
      drain: [Function: bound socketOnDrain],
      resume: [Function: onSocketResume],
      pause: [Function: onSocketPause]
    },
    _eventsCount: 8,
    _maxListeners: undefined,
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: false,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: true,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      constructed: true,
      prefinished: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: true,
      errored: null,
      closed: false,
      closeEmitted: false,
      [Symbol(kOnFinished)]: []
    },
    allowHalfOpen: true,
    _sockname: null,
    _pendingData: null,
    _pendingEncoding: '',
    server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _connections: 1,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      httpAllowHalfOpen: false,
      timeout: 0,
      keepAliveTimeout: 5000,
      maxHeadersCount: null,
      maxRequestsPerSocket: 0,
      headersTimeout: 60000,
      requestTimeout: 0,
      _connectionKey: '6::::8080',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 52
    },
    _server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _connections: 1,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      httpAllowHalfOpen: false,
      timeout: 0,
      keepAliveTimeout: 5000,
      maxHeadersCount: null,
      maxRequestsPerSocket: 0,
      headersTimeout: 60000,
      requestTimeout: 0,
      _connectionKey: '6::::8080',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 52
    },
    parser: HTTPParser {
      '0': [Function: bound setRequestTimeout],
      '1': [Function: parserOnHeaders],
      '2': [Function: parserOnHeadersComplete],
      '3': [Function: parserOnBody],
      '4': [Function: parserOnMessageComplete],
      '5': [Function: bound onParserExecute],
      '6': [Function: bound onParserTimeout],
      _headers: [],
      _url: '',
      socket: [Circular *1],
      incoming: [Circular *2],
      outgoing: null,
      maxHeaderPairs: 2000,
      _consumed: true,
      onIncoming: [Function: bound parserOnIncoming],
      [Symbol(resource_symbol)]: [HTTPServerAsyncResource]
    },
    on: [Function: socketListenerWrap],
    addListener: [Function: socketListenerWrap],
    prependListener: [Function: socketListenerWrap],
    setEncoding: [Function: socketSetEncoding],
    _paused: false,
    _httpMessage: ServerResponse {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: false,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: true,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: false,
      _headerSent: false,
      _closed: false,
      socket: [Circular *1],
      _header: null,
      _keepAliveTimeout: 5000,
      _onPendingData: [Function: bound updateOutgoingData],
      req: [Circular *2],
      _sent100: false,
      _expect_continue: false,
      locals: [Object: null prototype] {},
      statusCode: 201,
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    [Symbol(async_id_symbol)]: 58,
    [Symbol(kHandle)]: TCP {
      reading: true,
      onconnection: null,
      _consumed: true,
      [Symbol(owner_symbol)]: [Circular *1]
    },
    [Symbol(kSetNoDelay)]: false,
    [Symbol(lastWriteQueueSize)]: 0,
    [Symbol(timeout)]: null,
    [Symbol(kBuffer)]: null,
    [Symbol(kBufferCb)]: null,
    [Symbol(kBufferGen)]: null,
    [Symbol(kCapture)]: false,
    [Symbol(kBytesRead)]: 0,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(RequestTimeout)]: undefined
  },
  httpVersionMajor: 1,
  httpVersionMinor: 1,
  httpVersion: '1.1',
  complete: true,
  rawHeaders: [
    'Authorization',
    'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imp1bnloYXJhbmcxMjM0IiwiaWF0IjoxNjQ5Njg3MDAzLCJleHAiOjE2NDk2OTA2MDN9.DOI1Le0Qei59mWNkOYQB9gxu-5GaRl7S2bFPOZ4r4zw',
    'User-Agent',
    'PostmanRuntime/7.29.0',
    'Accept',
    '*/*',
    'Cache-Control',
    'no-cache',
    'Postman-Token',
    '686f19db-2236-4e57-9d9a-00705e9a1001',
    'Host',
    'localhost:8080',
    'Accept-Encoding',
    'gzip, deflate, br',
    'Connection',
    'keep-alive',
    'Content-Length',
    '0'
  ],
  rawTrailers: [],
  aborted: false,
  upgrade: false,
  url: '/api/user/test',
  method: 'POST',
  statusCode: null,
  statusMessage: null,
  client: <ref *1> Socket {
    connecting: false,
    _hadError: false,
    _parent: null,
    _host: null,
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: true,
      ended: false,
      endEmitted: false,
      reading: true,
      constructed: true,
      sync: false,
      needReadable: true,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: true,
      destroyed: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      dataEmitted: false,
      decoder: null,
      encoding: null,
      [Symbol(kPaused)]: false
    },
    _events: [Object: null prototype] {
      end: [Array],
      timeout: [Function: socketOnTimeout],
      data: [Function: bound socketOnData],
      error: [Function: socketOnError],
      close: [Array],
      drain: [Function: bound socketOnDrain],
      resume: [Function: onSocketResume],
      pause: [Function: onSocketPause]
    },
    _eventsCount: 8,
    _maxListeners: undefined,
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: false,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: true,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      constructed: true,
      prefinished: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: true,
      errored: null,
      closed: false,
      closeEmitted: false,
      [Symbol(kOnFinished)]: []
    },
    allowHalfOpen: true,
    _sockname: null,
    _pendingData: null,
    _pendingEncoding: '',
    server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _connections: 1,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      httpAllowHalfOpen: false,
      timeout: 0,
      keepAliveTimeout: 5000,
      maxHeadersCount: null,
      maxRequestsPerSocket: 0,
      headersTimeout: 60000,
      requestTimeout: 0,
      _connectionKey: '6::::8080',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 52
    },
    _server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _connections: 1,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      httpAllowHalfOpen: false,
      timeout: 0,
      keepAliveTimeout: 5000,
      maxHeadersCount: null,
      maxRequestsPerSocket: 0,
      headersTimeout: 60000,
      requestTimeout: 0,
      _connectionKey: '6::::8080',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 52
    },
    parser: HTTPParser {
      '0': [Function: bound setRequestTimeout],
      '1': [Function: parserOnHeaders],
      '2': [Function: parserOnHeadersComplete],
      '3': [Function: parserOnBody],
      '4': [Function: parserOnMessageComplete],
      '5': [Function: bound onParserExecute],
      '6': [Function: bound onParserTimeout],
      _headers: [],
      _url: '',
      socket: [Circular *1],
      incoming: [Circular *2],
      outgoing: null,
      maxHeaderPairs: 2000,
      _consumed: true,
      onIncoming: [Function: bound parserOnIncoming],
      [Symbol(resource_symbol)]: [HTTPServerAsyncResource]
    },
    on: [Function: socketListenerWrap],
    addListener: [Function: socketListenerWrap],
    prependListener: [Function: socketListenerWrap],
    setEncoding: [Function: socketSetEncoding],
    _paused: false,
    _httpMessage: ServerResponse {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: false,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: true,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: false,
      _headerSent: false,
      _closed: false,
      socket: [Circular *1],
      _header: null,
      _keepAliveTimeout: 5000,
      _onPendingData: [Function: bound updateOutgoingData],
      req: [Circular *2],
      _sent100: false,
      _expect_continue: false,
      locals: [Object: null prototype] {},
      statusCode: 201,
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    [Symbol(async_id_symbol)]: 58,
    [Symbol(kHandle)]: TCP {
      reading: true,
      onconnection: null,
      _consumed: true,
      [Symbol(owner_symbol)]: [Circular *1]
    },
    [Symbol(kSetNoDelay)]: false,
    [Symbol(lastWriteQueueSize)]: 0,
    [Symbol(timeout)]: null,
    [Symbol(kBuffer)]: null,
    [Symbol(kBufferCb)]: null,
    [Symbol(kBufferGen)]: null,
    [Symbol(kCapture)]: false,
    [Symbol(kBytesRead)]: 0,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(RequestTimeout)]: undefined
  },
  _consuming: false,
  _dumped: false,
  next: [Function: next],
  baseUrl: '',
  originalUrl: '/api/user/test',
  _parsedUrl: Url {
    protocol: null,
    slashes: null,
    auth: null,
    host: null,
    port: null,
    hostname: null,
    hash: null,
    search: null,
    query: null,
    pathname: '/api/user/test',
    path: '/api/user/test',
    href: '/api/user/test',
    _raw: '/api/user/test'
  },
  params: {},
  query: {},
  res: <ref *3> ServerResponse {
    _events: [Object: null prototype] { finish: [Function: bound resOnFinish] },
    _eventsCount: 1,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: false,
    chunkedEncoding: false,
    shouldKeepAlive: true,
    maxRequestsOnConnectionReached: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: true,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: false,
    _headerSent: false,
    _closed: false,
    socket: <ref *1> Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      parser: [HTTPParser],
      on: [Function: socketListenerWrap],
      addListener: [Function: socketListenerWrap],
      prependListener: [Function: socketListenerWrap],
      setEncoding: [Function: socketSetEncoding],
      _paused: false,
      _httpMessage: [Circular *3],
      [Symbol(async_id_symbol)]: 58,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    _header: null,
    _keepAliveTimeout: 5000,
    _onPendingData: [Function: bound updateOutgoingData],
    req: [Circular *2],
    _sent100: false,
    _expect_continue: false,
    locals: [Object: null prototype] {},
    statusCode: 201,
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] { 'x-powered-by': [Array] }
  },
  body: {},
  route: Route {
    path: '/api/user/test',
    stack: [ [Layer] ],
    methods: { post: true }
  },
  logIn: [Function (anonymous)],
  login: [Function (anonymous)],
  logOut: [Function (anonymous)],
  logout: [Function (anonymous)],
  isAuthenticated: [Function (anonymous)],
  isUnauthenticated: [Function (anonymous)],
  _sessionManager: SessionManager {
    _key: 'passport',
    _serializeUser: [Function: bound ]
  },
  authInfo: undefined,
  user: User {
    userId: 44,
    username: 'junyharang1234',
    password: '$2a$10$9pRXbk.wj75IA6p1j6ezueRP4TRwqBy3u5HV8dMfLixm5PVRGWSa.',
    nickname: '์ฃผ๋‹ˆํ•˜๋ž‘ํ•˜ํžˆ',
    userEmail: 'junyharang85923@gmail.com',
    userPhone: '01038384949'
  },
  [Symbol(kCapture)]: false,
  [Symbol(kHeaders)]: {
    authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imp1bnloYXJhbmcxMjM0IiwiaWF0IjoxNjQ5Njg3MDAzLCJleHAiOjE2NDk2OTA2MDN9.DOI1Le0Qei59mWNkOYQB9gxu-5GaRl7S2bFPOZ4r4zw',
    'user-agent': 'PostmanRuntime/7.29.0',
    accept: '*/*',
    'cache-control': 'no-cache',
    'postman-token': '686f19db-2236-4e57-9d9a-00705e9a1001',
    host: 'localhost:8080',
    'accept-encoding': 'gzip, deflate, br',
    connection: 'keep-alive',
    'content-length': '0'
  },
  [Symbol(kHeadersCount)]: 18,
  [Symbol(kTrailers)]: null,
  [Symbol(kTrailersCount)]: 0,
  [Symbol(RequestTimeout)]: undefined
}

Console์— ์ถœ๋ ฅ๋œ ๊ฒฐ๊ณผ์ธ ๊ฒƒ์ด์—์š”.

 

Console.log

์œ„์™€ ๊ฐ™์ด ์ •์ƒ์ ์œผ๋กœ ํšŒ์› ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

์ด ๊ณณ์— ๋ณด๋ฉด ํšŒ์›์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋…ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”. ์•„๋ฌด๋ฆฌ ์•”ํ˜ธํ™”๊ฐ€ ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•ด๋„ ํ•„์š”์—†๋Š” ๊ฐ’์ด ์˜ค๊ณ ๊ฐ€๋Š”๊ฑธ ์ฃผ๋‹ˆํ•˜๋ž‘์€ ์›์น˜ ์•Š๋Š” ๊ฒƒ์ด์—์š”.

 

 

jwt.strategy.ts

์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ์œ„ ๊ทธ๋ฆผ์—์„œ 47 ~ 49๋ฒˆ์งธ ์ค„์— DB ์กฐํšŒ ๋ถ€๋ถ„์—์„œ `select` Option์„ ํ†ตํ•ด ํšŒ์› ๊ณ ์œ  ๋ฒˆํ˜ธ, ํšŒ์› ID, ํšŒ์› Email์ฃผ์†Œ๋งŒ ์กฐํšŒํ•ด์„œ ๊ฐ€์ ธ์˜ค๋„๋ก ์ถ”๊ฐ€ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

Console.log

์ด์ œ ์›์น˜ ์•Š๋Š” ๊ฐ’์„ ์ œ์™ธํ•˜๊ณ , ์›ํ•˜๋Š” ๊ฐ’๋งŒ ์–ป์–ด์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

 

์ด์ „ ๊ธ€ : [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - JWT๋ฅผ ์ด์šฉํ•œ Login

๋‹ค์Œ ๊ธ€ : [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - Custom Decorator

 

 

 

 

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•