Programming Project ์ž‘์—…์‹ค/๋‚ด์šฉ ์ •๋ฆฌ

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

์ฃผ๋‹ˆ์“ฐ๐Ÿง‘‍๐Ÿ’ป 2022. 4. 11. 04:38
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'

 

 

 

 

 

 

 

 

 

๐Ÿš€ JWT๋ฅผ ์ด์šฉํ•œ Login

Swagger
Swagger

 

    ๐Ÿ”ฝ  ์„ค์น˜ํ•˜๊ธฐ

        ๐Ÿ“ฆ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์šฐ๋ฆฌ๋Š” `JWT`๋ฅผ ์ด์šฉํ•œ Login ๊ตฌํ˜„์„ ์œ„ํ•ด `Passport` Module๋„ ํ•จ๊ป˜ ์ด์šฉํ•  ๊ฒƒ์ด์—์š”.

์™œ๋ƒํ•˜๋ฉด ํ•ด๋‹น Module์ด `JWT`๋ฅผ ์ด์šฉํ•œ ์ธ์ฆ ์ฒ˜๋ฆฌ, ์ธ๊ฐ€ ์ฒ˜๋ฆฌ ๋“ฑ์˜ ๊ณผ์ •์„ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ธ ๊ฒƒ์ด์—์š”.

 

 

        ๐Ÿ“ฆ Module ์†Œ๊ฐœ

โ— @nestjs/jwt : `Nest.js`์—์„œ `JWT`๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” Module.
โ— @nestjs/passport : `Nest.js`์—์„œ `Passport`๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” Module.
โ— Passport : `Passport` Module.
โ— passport-jwt : `JWT` Module.

 

 

๋ช…๋ น์–ด

npm install @nestjs/jwt @nestjs/passport passport passport-jwt --save

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

 

 

 

 

 

    ๐Ÿ”ฝ  ๋“ฑ๋กํ•˜๊ธฐ

`auth Module` imports ๋ถ€๋ถ„์— ๋‚ด์šฉ์„ ๋„ฃ์–ด ์ค„ ๊ฒƒ์ด์—์š”. 

auth.modules.ts

๋จผ์ € ์ฃผ๋‹ˆํ•˜๋ž‘์€ `Configuration`์„ ํ†ตํ•˜์—ฌ yml์— ์ž‘์„ฑํ•œ JWT๊ด€๋ จ ๋‚ด์šฉ์„ 9๋ฒˆ์งธ ์ค„์ฒ˜๋Ÿผ ๊ฐ€์ ธ์˜จ ๋’ค ํ•ด๋‹น ๋‚ด์šฉ์„ 31, 32๋ฒˆ์งธ ์ค„์—์„œ ์ด์šฉํ•ด์„œ ๋ฏผ๊ฐ ์ •๋ณด๋ฅผ ์ˆจ๊ฒจ์ค€ ๊ฒƒ์ด์—์š”. ๋‹น์—ฐํžˆ ์ด ์ •๋ณด๋“ค์€ `.gitignore`์—๋„ ๋“ฑ๋ก์ด ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ๋‹ˆํ•˜๋ž‘ ๋ง๊ณ ๋Š” ๋ˆ„๊ตฌ๋„ ํ™•์ธํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด์—์š”.

`Configuration`์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ `์ด ๊ณณ`์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ด ๋‘˜๊ฒŒ์š”.

 

31๋ฒˆ์งธ ์ค„ `secret`์€ Token์„ ๋งŒ๋“ค ๋•Œ ์ด์šฉํ•˜๋Š” ๋น„๋ฐ€ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ด์—์š”. ํ‰๋ฌธ์œผ๋กœ ์ž…๋ ฅํ•ด๋„ ๋˜๊ณ , ์ฃผ๋‹ˆํ•˜๋ž‘์€ ํ‰๋ฌธ์„ base 64๋กœ Encodingํ•œ ๊ฐ’์„ ๋„ฃ์–ด ์ค€ ๊ฒƒ์ด์—์š”.

`signOptions`์—์„œ ์„œ๋ช…์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ •์˜ํ•ด ์ฃผ๋Š” ๊ณณ์ธ ๊ฒƒ์ด์—์š”.

32๋ฒˆ์งธ ์ค„ `ExpireIn`์€ Token ๋งŒ๋ฃŒ ์‹œ๊ฐ„์„ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

 

 

        ๐Ÿ“ฆ Passport ๋“ฑ๋กํ•˜๊ธฐ

auth.modules.ts

32๋ฒˆ์งธ ์ค„์— ์ƒˆ๋กœ์šด ์‹๊ตฌ๊ฐ€ ์ƒ๊ธด๊ฒƒ์ด์—์š”. ๋ฐ”๋กœ `PassportModule`์•ˆ์— `register()`๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ๊ทธ ์•ˆ์— ๊ธฐ๋ณธ ์ „๋žต ๊ฐ’์œผ๋กœ `JWT`๋ฅผ ๋„ฃ์–ด์ค˜์„œ `JWT`๋ฅผ ์ด์šฉํ•œ Login ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

 

์ด์ œ `Service`์—์„œ `SignIn` Method๋ฅผ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ธ๋ฐ, ์œ„์—์„œ auth Module์— JWT๋ฅผ ๋“ฑ๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— `Service`์—์„œ `JWT` ๋‚ด์šฉ์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

auth.service.ts

์œ„์™€ ๊ฐ™์ด ์ƒ์„ฑ์ž ๋ถ€์— `userRepository`๋ฅผ `DI(Dependency Injection)` ํ•ด์ฃผ์—ˆ๋“ฏ์ด `JWT`๋„ ๋™์ผํ•˜๊ฒŒ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

        ๐Ÿ“ฆ DTO ๋งŒ๋“ค๊ธฐ

auth.signin.request.dto.ts

๋กœ๊ทธ์ธ์„ ํ•  ๋•Œ, ID์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‹ด๊ธฐ ์œ„ํ•œ DTO๋ฅผ ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

์—ญ์‹œ `Pipe`๋ฅผ ์ด์šฉํ•œ Validation์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ Decorator๊ฐ€ ๋ถ„๋น„ ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

 

        ๐Ÿ“ฆ Service

auth.service.ts - signIn() : 134 ~ 174

๋จผ์ € `Service` ๋ถ€๋ถ„์„ ์‚ดํŽด ๋ณผ ๊ฒƒ์ด์—์š”. ์ตœ์ดˆ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ DTO๋ฅผ ๋ฐ›๊ณ  ๊ทธ DTO ๋‚ด์šฉ์„ ID, Password๋กœ ๋‚˜๋ˆ„๊ธฐ ์œ„ํ•ด ๊ฐ๊ฐ ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋’ค 146๋ฒˆ์งธ ์ค„์— `Repository`์— `findOne()`์„ ํ†ตํ•ด `Select`๋ฅผ ํ•˜๋Š”๋ฐ, ์ฃผ๋‹ˆํ•˜๋ž‘์€ ID์™€ Password ๊ฐ’๋งŒ ํ•„์š”ํ•ด์„œ `Select` Option์„ 147๋ฒˆ ์ค„๊ณผ ๊ฐ™์ด ์ฃผ๊ณ , `where` Option์„ ํ†ตํ•ด ์š”์ฒญ์œผ๋กœ ๋“ค์–ด์˜จ ID๋กœ ID๋ฅผ ์ฐพ๊ฒŒ ํ•œ ๊ฒƒ์ด์—์š”.

152๋ฒˆ์งธ ์ค„์—์„œ ํ•ด๋‹น ๊ฐ’์ด ์žˆ๋Š”์ง€์™€ ํ•จ๊ป˜ ์ด์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์•”ํ˜ธํ™” Data Base์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์•”ํ˜ธ๊ฐ€ ๊ฐ™์€์ง€๋ฅผ ๋น„๊ตํ•œ ๋’ค ๋ชจ๋‘ ์ฐธ(&& And ์—ฐ์‚ฐ์ž)์ด๋ผ๋ฉด payload ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜์— ID๊ฐ’์„ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

156๋ฒˆ์งธ ์ค„์— `jwtService`์— `sing()`์„ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, payload ๋ณ€์ˆ˜ ๊ฐ’์„ ๋ณด๋‚ด ์ „์ž ์„œ๋ช…์ด ์ด๋ค„์ง€๊ฒŒ ๋งŒ๋“ค๊ณ , ์ด๋ฅผ accessToken ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

158 ~ 163๋ฒˆ์งธ๋Š” `Response(์‘๋‹ต)` ๊ฐ’์— ์œ„์™€ ๊ฐ™์ด HTTP Status Code์™€ ํ•œ๊ธ€ Message, ์˜์–ด Message๋ฅผ ์ „๋‹ฌํ•˜๊ณ , data Key์— accessToken ๊ฐ’์„ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

์ด ๋‚ด์šฉ์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด Method ๋ฐ˜ํ™˜ Type์„ ๋ณด๋ฉด Promise๋ฅผ ์ด์šฉํ•˜๊ณ , ๋งŽ์€ ๋ณ€์ˆ˜๋“ค์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด์—์š”.

๋งŒ์•ฝ If๋ฌธ์— ํ†ต๊ณผํ•˜์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด Login์ด ์‹คํŒจํ–ˆ๋‹ค๋Š” ์ •๋ณด๋ฅผ ๋ณด๋‚ผ ๊ฒƒ์ด์—์š”.

 

auth.service.ts - signIn() : 178 ~ 186

Login์€ ๋‘๊ฐ€์ง€ ๊ฒฐ์ •์ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”. Login์ด ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜, Login์ด ์‹คํŒจํ•˜๊ฑฐ๋‚˜, ์‹คํŒจ๋ฅผ ํ–ˆ๋‹ค๋Š” ๊ฑด ID ํ˜น์€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž˜ ๋ชป ์ž…๋ ฅํ•ด์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฐ๊ณผ์ผ ๊ฒƒ์ด์—์š”.

๊ทธ ๋‚ด์šฉ์€ ์œ„์—์„œ ๋‹ค ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์คฌ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด Server ๋ฌธ์ œ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์ž‡๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋ž˜์„œ ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑ์„ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

 

        ๐Ÿ“ฆ Controller

auth.controller.ts

๋ฐ˜์‘ํ˜•

Controller๋Š” ์ตœ์ดˆ `Service`์˜ `signIn()`์„ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ์ด์šฉ์ž๊ฐ€ Login์„ ์œ„ํ•ด ์ž…๋ ฅํ•œ ๊ฐ’์„ ๋‹ด์€ DTO๋ฅผ ์ „๋‹ฌํ•ด์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋’ค ๋ฐ˜ํ™˜๊ฐ’์ด ๋Œ์•„์˜ค๋ฉด ์œ„์— `Service`์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ’๋“ค์ด ์ €๋ ‡๊ฒŒ ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฃŒํ˜• Type์„ ์ €๋ ‡๊ฒŒ ์ค€ ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜ loginUser ๋ณ€์ˆ˜์— ๊ฐ’์„ ๋‹ด์•„ res.status()๋ฅผ ํ˜ธ์ถœํ•ด์„œ 200์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์ „๋‹ฌํ•˜๊ณ , `Service`์—์„œ ๋งŒ๋“  Data๊ฐ€ `JSON` ํ˜•ํƒœ๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

 

 

 

    ๐Ÿ”ฝ  ๊ฒฐ๊ณผ

        ๐Ÿ“ฆ POSTMAN

Postman Test

์ •์ƒ์ ์œผ๋กœ Data๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ณ  ์žˆ๊ณ , Access Token๊นŒ์ง€ ์ž˜ ์˜ค๊ณ  ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

์•„์ง `Vue.js`์—์„œ Login ๋ถ€๋ถ„์ด ๊ตฌํ˜„์ด ๋˜์ง€ ์•Š์•„ `Vue.js`์—์„œ๋Š” ๋‹ค์Œ ํฌ์ŠคํŒ…์— ์ค€๋น„ ํ•ด ๋‘๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ธ๊ฐ€ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๊ณต๋ถ€ํ•ด ๋ณด๋„๋ก ํ•  ๊ฒƒ์ด์—์š”.

 

 

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

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

 

 

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•