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

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

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

 

 

 

 

 

 

 

 

 

๐Ÿš€ ํšŒ์› ๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„

Swagger

 

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

DB User Table

์ด๋ฒˆ `Nest.js`๋ฅผ ํ†ตํ•œ Project๋Š” ๊ธฐ์กด์— `Spring Boot`๋กœ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ๋˜ Project๋ฅผ ๋”ฐ๋ผํ•ด๋ณด๋ฉด์„œ ๊ณต๋ถ€ํ•ด ๋ณด๋Š”๋ฐ ๊ทธ ์ดˆ์ ์ด ๋งž์ถฐ์ง„ Project์ธ ๊ฒƒ์ด์—์š”.

๋”ฐ๋ผ์„œ ์ด๋ฏธ Table์ด ์กด์žฌํ•˜๊ณ , ์ด Table์„ ์ด์šฉํ•ด์„œ Project๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

        ๐Ÿ“ฆ Nest CLI๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐ ๊ตฌ์„ฑ - Module

๋ช…๋ น์–ด

nest g module {Module-Name}

 

$ nest g module {Module-Name}

 

 

auth.module.ts Directory ๊ตฌ์กฐ

`Nest CLI`๋ฅผ ํ†ตํ•ด ์œ„์™€ ๊ฐ™์ด Module์„ ์ƒ์„ฑํ•˜๋ฉด Directory๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ์•Œ์•„์„œ ๋งŒ๋“ค์–ด ์ง€๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

        ๐Ÿ“ฆ Nest CLI๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐ ๊ตฌ์„ฑ - Controller

๋ช…๋ น์–ด

nest g controller {Contorller-Name} {--no-spec}

 

$ nest g controller {Controller-Name} {--no-spec}

 

 

auth.controller.ts Directory ๊ตฌ์กฐ

 

 

 

        ๐Ÿ“ฆ Nest CLI๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐ ๊ตฌ์„ฑ - Service

๋ช…๋ น์–ด

nest g service {Service-Name} {--no-spec}

 

$ nest g service {Service-name} {--no-spec}

 

 

auth.service.ts Directory ๊ตฌ์กฐ

 

 

 

 

๋ช…๋ น์–ด์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ `์ด ๊ณณ`์— ์ค€๋น„ ํ•ด ๋‘์—ˆ์–ด์š”!

 

 

 

 

        ๐Ÿ“ฆ User Entity ๋งŒ๋“ค๊ธฐ

user.entity.ts

์ตœ์ดˆ `User Entity`๋Š” ์œ„์™€ ๊ฐ™์ด ์ƒ์„ฑํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

 

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

user.repository.ts

`Repository`๋Š” ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

์ฐธ๊ณ ๋กœ `Repository`์™€ `Eentity`๋Š” ๋ช…๋ น์–ด๊ฐ€ ์•„๋‹Œ ์ง์ ‘ `TypeScript File`์„ ๋งŒ๋“ค์–ด์„œ ์ง„ํ–‰ํ•œ ๊ฒƒ์ด์—์š”.

 

auth Directory ๊ตฌ์กฐ

 

์ด๋ฒˆ์—๋Š” ์ƒ์„ฑ๋œ `User Repository`๊ฐ€ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ์ด์šฉ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ `auth Module`์— `import`๋ฅผ ์‹œ์ผœ์ค„ ๊ฒƒ์ด์—์š”.

 

auth.module.ts

9๋ฒˆ์งธ ์ค„๊ณผ ๊ฐ™์ด `TypeOrmModule forFeture()`๋ฅผ ์ด์šฉํ•˜์—ฌ `auth Module`์•ˆ์— ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ `UserRepository`์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋“ฑ๋กํ•ด ์ค€ ๊ฒƒ์ด์—์š”. 

์ฐธ๊ณ ๋กœ ๋ช…๋ น์–ด๋กœ ๋งŒ๋“ค์—ˆ๋˜ `Controller`์™€ `Service`๋Š” ์ž๋™์œผ๋กœ ๋“ฑ๋ก ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

 

์ด๋ฒˆ์—๋Š” `User Repository`๋ฅผ `auth Service`์—์„œ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด `DI(Dependency Injection)` ํ•ด ์ค„ ๊ฒƒ์ด์—์š”.

 

auth.service.ts

์œ„์™€ ๊ฐ™์ด `์ƒ์„ฑ์ž ์ฃผ์ž…`์„ ํ†ตํ•ด `User Repositoy`๋ฅผ `DI(Dependency Injection)` ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  ๊ธฐ๋Šฅ ๊ตฌํ˜„

Swagger

 

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

์ตœ์ดˆ `Client`๊ฐ€ `Request(์š”์ฒญ)`์„ ๋ณด๋‚ผ ๋•Œ ๊ทธ๊ฒƒ์„ ๋‹ด์„ ๊ทธ๋ฆ‡์„ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ด์—์š”.

 

/src/auth/dto/auth-credential.dto.ts

์œ„์™€ ๊ฐ™์ด `Pipe`๋ฅผ ์ด์šฉํ•œ `์œ ํšจ์„ฑ ๊ฒ€์‚ฌ(Validation)` ๊นŒ์ง€ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” DTO๋ฅผ ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

`Pipe`์— ๋Œ€ํ•ด ์•Œ๊ณ  ์‹ถ์œผ์‹  ๋ถ„๋“ค์„ ์œ„ํ•ด `์ด ๊ณณ`์— ์ค€๋น„ ํ•ด ๋‘” ๊ฒƒ์ด์—์š”.

 

 

โ–บ ๋ณ€๊ฒฝ ์‚ฌํ•ญ

/src/auth/dto/auth-credential.dto.ts

๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋ฉด ๋จผ์ € `@ApiProperty` Decorator(JAVA = Annotaion)์„ ์ถ”๊ฐ€ ํ•ด ์คฌ๋Š”๋ฐ,

 

Project Swagger

Swagger์—์„œ ์œ„์™€ ๊ฐ™์ด ๊ฐ Property(JAVA = Member ๋ณ€์ˆ˜)์— ๋Œ€ํ•œ ์„ค๋ช…์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ์ด์—์š”.

 

๊ทธ๋ฆฌ๊ณ , `Pipe`๋ฅผ ์ด์šฉํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด `@IsNotEmpty() = ๋น„์–ด ์žˆ๋Š” ๊ฐ’์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ`, `@IsString() = ์ž…๋ ฅ๊ฐ’์ด ๋ฌธ์ž์—ด์ธ์ง€ ๊ฒ€์‚ฌ`, `@IsEmail = ์ž…๋ ฅ๊ฐ’์ด Mail ํ˜•ํƒœ์ธ์ง€ ๊ฒ€์‚ฌ`๋ฅผ ์‚ฌ์šฉํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

        ๐Ÿ“ฆ Repository ๊ตฌํ˜„

ํšŒ์›๊ฐ€์ž…์ด๋ž€ ๊ธฐ๋Šฅ์€ `CRUD`์—์„œ `C(Create)`์— ํ•ด๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— `Repository`์—์„œ Data Base์—๊ฒŒ Insert Query๋ฅผ ๋‚ ๋ฆด ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

user.repository.ts - signUp()

๋ฐ˜์‘ํ˜•

28๋ฒˆ์งธ ์ค„์— ์š”์ฒญ ๋‚ด์šฉ์„ ๋‹ด์€ DTO์— ๋“ค์–ด ์žˆ์„ ๋‚ด์šฉ๋“ค์„ ๊ฐ๊ฐ์˜ ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜์— ๋‹ด์•„์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋’ค `create()`์„ ์ด์šฉํ•ด์„œ ๊ทธ ๊ฐ๊ฐ์˜ ๋ณ€์ˆ˜๋“ค์€ ์ƒ์ˆ˜ํ˜• ๊ฐ์ฒด user๋ฅผ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

๊ทธ๋ฆฌ๊ณ , `save()`๋ฅผ ํ†ตํ•ด Data Base์— Insert Query๊ฐ€ ๋‚ ์•„๊ฐ€๋Š”๋ฐ, ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋‹ด์•„ ๋‚ ์•„๊ฐ€๊ฒŒ ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

์—ฌ๊ธฐ์„œ `Promise`, `async`, `await`์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ `์ด ๊ณณ`์— ์ค€๋น„ ํ•ด ๋‘” ๊ฒƒ์ด์—์š”.

๋ฐ˜ํ™˜ Type์— `Promise`๋ฅผ ๋„ฃ๊ณ , ์–ด๋–ค ๋ฐ˜ํ™˜๊ฐ’๋„ ์—†์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— `<void>`๋ฅผ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

Data Base์˜ ์ž‘์—…์ด ์ฒ˜๋ฆฌ ๋  ๋•Œ๊นŒ์ง€ `await`์„ ๋งŒ๋‚œ `JavaScript`๋Š” ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ์žˆ๋‹ค๊ฐ€ Data Base์ž‘์—…์ด ๋๋‚˜๋ฉด ๊ทธ ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

 

 

โ–บ ๋ณ€๊ฒฝ ์‚ฌํ•ญ

user.repository.ts - signUp()

์ฃผ๋‹ˆํ•˜๋ž‘์€ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์—ˆ๋‹ค๋ฉด `Response(์‘๋‹ต) Data`๋ฅผ ์–ป๊ณ  ์‹ถ์€ ๊ฒƒ์ด์—์š”.

๊ทธ๋ž˜์„œ ๋ฐ˜ํ™˜ Type(220๋ฒˆ์งธ ์ค„ - Promise<{...}>)๋ฅผ ํ†ตํ•ด `return(238 ๋ฒˆ์งธ ์ค„)`์— ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•ด์ค€ ๊ฒƒ์ด์—์š”. 

 

 

 

        ๐Ÿ“ฆ Service ๊ตฌํ˜„

auth.service.ts

`Service`๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ Layer์ธ ๊ฒƒ์ด์—์š”. ์ด๊ณณ์—์„œ๋Š” ๋”ฑํžˆ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ด ์—†์–ด ๋ฐ”๋กœ `Repository`๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ๋ฐ˜ํ™˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

        ๐Ÿ“ฆ Contoller ๊ตฌํ˜„

auth.controller.ts

`Spring Boot`์—์„œ API URI๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ตœ์ดˆ Class ์ด๋ฆ„ ์œ„์— `@RequestMapping`์„ ์ด์šฉํ•ด์„œ `/api/user`์™€ ๊ฐ™์ด ์ž…๋ ฅ์„ ํ•ด์ฃผ์—ˆ๋Š”๋ฐ, `Nest.js`์—์„œ๋Š” URI ๋งจ ์•ž์— '/'๋ฅผ ์ œ๊ฑฐํ•ด์„œ ์ž…๋ ฅํ•ด ์ค˜์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

29 ~ 30๋ฒˆ์งธ ์ค„์€ Swagger ์„ค์ • ๋ถ€๋ถ„์ด์—์š”.

29๋ฒˆ์งธ ์ค„ `@ApiOeration`์€ ์œ„์™€ ๊ฐ™์ด 'ํšŒ์› ์ธ์ฆ / ์ธ๊ฐ€ API'๋ผ๋Š” ํ‘œ์‹œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํ•ด๋‹น API ์„ค๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ๋Š” ๋ถ€๋ถ„์ธ ๊ฒƒ์ด์—์š”.

30๋ฒˆ์งธ ์ค„์€ `Response`์— HTTP Status Code์— ๋”ฐ๋ผ ํ•ด๋‹น Code๊ฐ€ ์–ด๋–ค ๋‚ด์šฉ์ธ์ง€๋ฅผ ์„ค๋ช…ํ•ด ์ฃผ๋Š” ๋ถ€๋ถ„์ธ ๊ฒƒ์ด์—์š”.

 

auth.controller.ts - signUp()

<์œ„์— ๋ถ€๋ถ„์—์„œ ์ˆ˜์ • ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!>

 

93๋ฒˆ์งธ ์ค„์— `@Post`๋ฅผ ํ†ตํ•ด ํ•ด๋‹น Method๋Š” HTTP Method Post๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๊ณ , URI ๋งˆ์ง€๋ง‰์— `/signup`์ด ๋“ค์–ด์™€์•ผ ํ˜ธ์ถœ ๋˜๊ฒŒ ํ•ด ์ค€๊ฒƒ์ด์—์š”. ๊ทธ๋Ÿฐ ๋’ค ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ํšŒ์› ๊ฐ€์ž… ์‹œ ์ž‘์„ฑํ•ด์•ผ ํ•  ๋‚ด์šฉ์„ ๋‹ด์€ DTO๋ฅผ ๋ฐ›๊ณ , `@Res()`๋ฅผ ๋ฐ›๋Š”๋ฐ, ์ด ๋‚ด์šฉ์€ `์ด ๊ณณ`์— ๋”ฐ๋กœ ์ค€๋น„ ํ•ด ๋‘” ๊ฒƒ์ด์š”.

์ด๋ฅผ ํ†ตํ•ด 101๋ฒˆ์งธ ์ค„์— ๋ฐ˜ํ™˜์„ ํ•  ๋•Œ `res.status()`๋ฅผ ํ†ตํ•ด Http Status Code์™€ `JSON` ํ˜•ํƒœ๋กœ Data๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

99๋ฒˆ์งธ ์ค„์„ ๋ณด๋ฉด ๋จผ์ € `DI(Dependency Injection)`ํ•œ `Service`์˜ signUp()์„ ํ˜ธ์ถœํ•ด์„œ DTO๋ฅผ ๋ณด๋‚ด๊ณ , ํ•ด๋‹น ์ž‘์—…์ด ์ฒ˜๋ฆฌ ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ ์‹œํ‚ค๊ธฐ ์œ„ํ•ด `await`์„ ์„ ์–ธํ•œ ๊ฒƒ์ด์—์š”. ๊ทธ๋ ‡๊ฒŒ ๋ฐ˜ํ™˜๊ฐ’์ด ์˜ค๊ฒŒ ๋˜๋ฉด `UserEntity` Type์˜ ์ƒ์ˆ˜ํ˜• ๊ฐ์ฒด user์— ๊ฐ’์ด ๋‹ด๊ธฐ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์—์š”.

์ž๋ฃŒํ˜• Type์ด ๋“ค์–ด๊ฐ€๋Š” ๊ณณ์— ์—ฌ๋Ÿฌ ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์€ Respository์—์„œ HTTP Response์— ๋งž๊ฒŒ ๋‹ต๋ณ€์„ ์ฃผ๊ธฐ ์œ„ํ•ด์„œ ์ž‘์—…์„ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ธ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  ๊ฒฐ๊ณผ

        ๐Ÿ“ฆ POSTMAN

์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ Postman์„ ํ†ตํ•ด Test ํ•ด ๋ณผ ๊ฒƒ์ด์—์š”.

 

Postman Test ๊ฒฐ๊ณผ

์•„์ฃผ ์ž˜ ๋˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

Data Base User Table

Data Base๋ฅผ ํ™•์ธ ํ•ด ๋ณด๋‹ˆ 9๋ฒˆ์งธ ์ค„์— ์ •์ƒ์ ์œผ๋กœ Data๊ฐ€ ์ž…๋ ฅ ๋œ ๊ฒƒ์ด์—์š”.

 

 

 

 

 

๐Ÿš€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

 

auth.credential.dto

์œ„์™€ ๊ฐ™์ด DTO๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์ด์—์š”.

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด ์„ธ ๊ฐ€์ง€๊ฐ€ ๋” ์ถ”๊ฐ€๊ฐ€ ๋˜์—ˆ๋Š”๋ฐ, `@MinLength() = ์ตœ์†Œ ์ž…๋ ฅ๋˜์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ž์˜ ๊ฐœ์ˆ˜`, `@MaxLenth() = ์ตœ๋Œ€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ž์˜ ๊ฐœ์ˆ˜`, `@Mathces() = ์ •๊ทœ ํ‘œํ˜„์‹์„ ์ด์šฉํ•œ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž ๋“ฑ๋ก`์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด์—์š”. ๊ทธ๋ฆฌ๊ณ  `@Mathces() = ์ •๊ทœ ํ‘œํ˜„์‹์„ ์ด์šฉํ•œ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž ๋“ฑ๋ก`์—์„œ `message`๋ฅผ ํ†ตํ•ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์œ„๋ฐ˜๋˜๋ฉด ๊ฒฝ๊ณ  Message๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

์ •๊ทœ ํ‘œํ˜„์‹๊ณผ ๊ฐ™์€ ๊ฒƒ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ `Spring Boot` Project๋ฅผ ํ•˜๋ฉด์„œ `์ด ๊ณณ`์— ์ค€๋น„ ํ•ด ๋‘” ๊ฒƒ์ด์—์š”.

 

auth.controller.ts - signUp()

`Controller`์—์„œ `Pipe`๋ฅผ ์ด์šฉํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” 93๋ฒˆ์งธ ์ค„์— ๋งค๊ฐœ ๋ณ€์ˆ˜ ์ชฝ์„ ๋ณด๋ฉด `@Body()`์•ˆ์— `ValidationPipe`๋ฅผ ๊ผญ ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์œ„์™€ ๊ฐ™์ด ํ•ด์ค˜์•ผ `Request(์š”์ฒญ)`์ด ๋“ค์–ด์™”์„ ๋•Œ, Method๊ฐ€ ๋™์ž‘ํ•˜๊ธฐ ์ „์— DTO์— ์ž…๋ ฅ๋œ Decorator๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ Validation์„ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

 

    ๐Ÿ”ฝ  ๊ฒฐ๊ณผ

        ๐Ÿ“ฆ POSTMAN

 

Postman Test

์œ„์™€ ๊ฐ™์ด ์ •์ƒ์ ์œผ๋กœ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์ง„ํ–‰๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

 

๐Ÿš€ ID Unique Value Config

Swagger

 

 

์ด๋ฒˆ์—๋Š” ํšŒ์› ๊ฐ€์ž…์„ ํ•  ๋•Œ, ๋ณ„๋ช…, ID๊ฐ€ ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค๋ฉด `Error`๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๊ฒƒ์ด์—์š”.

์ด ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐ ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

โ— `Repository`์—์„œ `findOne()`์„ ์ด์šฉํ•ด์„œ ์ด๋ฏธ ๊ฐ™์€ Data๊ฐ€ ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ณ , ์—†๋‹ค๋ฉด Data ์ €์žฅ.
     - ๋‹จ์  : Data Base์— ๋‘๋ฒˆ ์ ‘๊ทผ.
โ— Data Base Level์—์„œ ๋งŒ์•ฝ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง„ ํšŒ์›์ด ์žˆ๋‹ค๋ฉด `Error`๋ฅผ ๋˜์ ธ์ฃผ๋Š” ๋ฐฉ๋ฒ•.

๋จผ์ € ๋‘๋ฒˆ์งธ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•  ๊ฒƒ์ด์—์š”.

์ตœ์ดˆ `user.entity.ts`์— Class ์œ„์— `@Unique()`๋ฅผ ์ด์šฉํ•˜์—ฌ ์ค‘๋ณต์„ ๋ง‰๊ณ ์žํ•˜๋Š” ๊ฐ’๋“ค์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

 

user.entity.ts

 

user.repository.ts

`Repository`์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ–ˆ์„ ๋•Œ, try - catch ๊ตฌ๋ฌธ์„ ์ด์šฉํ•ด์„œ `Error` Mesaage๋ฅผ Handlingํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

 

 

์ฃผ๋‹ˆํ•˜๋ž‘์€ `Spring Boot` Project์—์„œ ์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•๊ณผ ๊ฐ™์ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๊ตฌ์„ฑํ•œ ๊ฒƒ์ด์—์š”.

๋ฌผ๋ก  SQL ๋ฌธ์ด ๋‘๋ฒˆ ๋‚ ์•„๊ฐ€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์ง€๋งŒ, ์ผ๋‹จ `Spring Boot`์™€ ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๋ณด๋„๋ก ํ•  ๊ฒƒ์ด์—์š”.

 

์ฐธ๊ณ ๋กœ ID, ๋ณ„๋ช…, Email, ํ•ธ๋“œํฐ ๋ฒˆํ˜ธ๊นŒ์ง€ ๋ชจ๋‘ ์ค‘๋ณต ์ฒดํฌ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ID์— ๋Œ€ํ•œ ๋‚ด์šฉ๋งŒ ์ •๋ฆฌ ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

   /**
     * ํšŒ์› ๊ฐ€์ž… ์ „ ๋“ฑ๋ก๋œ ID ์ •๋ณด ์ธ์ง€ ํ™•์ธ
     * @param authDuplicateByUserIdDto - ํšŒ์› ๊ฐ€์ž… ์ „ ๋“ฑ๋ก ๋˜์–ด ์žˆ๋Š” ID ์ธ์ง€ ํ™•์ธ์„ ์œ„ํ•œ ์ด์šฉ์ž ์ž…๋ ฅ ์ •๋ณด DTO
     * @return User - ํ•ด๋‹น ํšŒ์›์˜ ์ •๋ณด ๋ฐ˜ํ™˜
     * @see ""
     */

    async duplicateUserID(authDuplicateByUserIdDto: AuthDuplicateByUserIdDto): Promise<{ messageKo: string; statusCode: number; data: User; messageEn: string }> {

        this.logger.log("UserRepository์˜ duplicateUserID(authDuplicateByUserIdDto: AuthDuplicateByUserIdDto)์ด ํ˜ธ์ถœ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!");
        this.logger.log(`Service๋กœ ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ DTO ๋‚ด์šฉ : ${authDuplicateByUserIdDto.toString()}`);
        this.logger.log(`DB์— Select()๋ฌธ์„ ํ†ตํ•ด ํ•ด๋‹น ID๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!`);

        const { username } = authDuplicateByUserIdDto;

        this.logger.log(`username : ${username}`)

        const findByUserID = await this.findOne({
            where: { username : username}
        });

        this.logger.log(`DB์—์„œ ์กฐํšŒ๋œ ๊ฐ’ : ${findByUserID}`);

        if (findByUserID) {

            this.logger.log("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ID ์ž…๋‹ˆ๋‹ค! 409 Code์™€ ํ•จ๊ป˜ \"์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’ ์ž…๋‹ˆ๋‹ค!\" ๋ฐ˜ํ™˜ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!")

            return {
                statusCode: 409,
                messageKo: "์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’ ์ž…๋‹ˆ๋‹ค!",
                messageEn: "Conflict",
                data: findByUserID,
            };

        } else {

            this.logger.log("์ค‘๋ณต ๋˜๋Š” ๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค! 200 Code์™€ ํ•จ๊ป˜ \"์‚ฌ์šฉ ๊ฐ€๋Šฅ!\" ๋ฐ˜ํ™˜ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!");

            return {
                statusCode: 200,
                messageKo: "์‚ฌ์šฉ ๊ฐ€๋Šฅ!",
                messageEn: "OK",
                data: findByUserID,
            };
        } // if (findByUserID === null || findByUserID === undefined) ๋
    }   // duplicateUserID(authDuplicateByUserIdDto: AuthDuplicateByUserIdDto) ๋

๋จผ์ € `Repository`๋ถ€ํ„ฐ ์‚ดํŽด ๋ณผ ๊ฒƒ์ด์—์š”. ์ตœ์ดˆ 39๋ฒˆ์งธ ์ค„์— ๋ณด๋ฉด ์ž…๋ ฅ์œผ๋กœ ๋“ค์–ด์˜จ DTO์—์„œ `username` ๋‚ด์šฉ์„ ๋นผ๊ธฐ ์œ„ํ•ด ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜ username์— ๊ฐ’์„ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋’ค `findOne() = select * from user where username = ${username]`์„ ์ด์šฉํ•ด์„œ DB์—์„œ Client๊ฐ€ ID ์ค‘๋ณต์ฒดํฌ๋ฅผ ์œ„ํ•ด ์ „๋‹ฌํ•œ ๊ฐ’ ID ๊ฐ’์ด ์žˆ๋Š”์ง€ ์กฐํšŒํ•˜๋„๋ก ํ•œ ๊ฒƒ์ด์—์š”.

`findOne()`์— ๋ณด๋ฉด options๋กœ `where`๋ฅผ ํ†ตํ•ด `username`์„ ์กฐํšŒํ•˜๋Š”๋ฐ, [where : { username : username}] ๋ถ€๋ถ„์€ ์ƒ์ˆ˜ ํ˜• ๋ณ€์ˆ˜ username์ด ๊ฐ€์ง„ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์กฐํšŒํ•˜๋ผ๊ณ  ํ•œ ๊ฒƒ์ด์—์š”.

์ด๋ ‡๊ฒŒ ์•ˆํ•˜๋ฉด ์—‰๋šฑํ•˜๊ฒŒ `userId` Column์—์„œ ์ฐพ๊ณ  ์žˆ๋”๋ผ๊ตฌ์š”.

 

๐Ÿ’ก ์ฐธ๊ณ  ์‚ฌํ•ญ
TypeORM SQL Show
JPA์—์„œ Console์„ ํ†ตํ•ด SQL๋ฌธ์ด ์–ด๋–ป๊ฒŒ ๋˜์ ธ์ง€๋Š”์ง€๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”.
MyBatis ์—ญ์‹œ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๊ตฌ์š”.

TypeORM๋„ ์ด ๊ธฐ๋Šฅ์ด ์žˆ๋Š”๋ฐ, 

typeorm.config.ts

์œ„์˜ ๊ทธ๋ฆผ 14๋ฒˆ์งธ ์ค„์ฒ˜๋Ÿผ logging์„ all๋กœ ํ•ด์ฃผ๋ฉด Error๋Š” ๋ฌผ๋ก ์ด๊ณ , SQL ๋ฌธ์ด ์–ด๋–ป๊ฒŒ ๋˜์ ธ์ง€๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

SQL Logging

 

   /**
     * ํšŒ์› ๊ฐ€์ž… ์ „ ๋“ฑ๋ก๋œ ID ์ •๋ณด ์ธ์ง€ ํ™•์ธ
     * @param authDuplicateByUserIdDto - ํšŒ์› ๊ฐ€์ž… ์ „ ๋“ฑ๋ก ๋˜์–ด ์žˆ๋Š” ID ์ธ์ง€ ํ™•์ธ์„ ์œ„ํ•œ ์ด์šฉ์ž ์ž…๋ ฅ ์ •๋ณด DTO
     * @return User - ํ•ด๋‹น ํšŒ์›์˜ ์ •๋ณด ๋ฐ˜ํ™˜
     * @see ""
     */

    async duplicateUserID(authDuplicateByUserIdDto: AuthDuplicateByUserIdDto): Promise<{ messageKo: string; statusCode: number; data: User; messageEn: string }> {

        this.logger.log("UserRepository์˜ duplicateUserID(authDuplicateByUserIdDto: AuthDuplicateByUserIdDto)์ด ํ˜ธ์ถœ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!");
        this.logger.log(`Service๋กœ ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ DTO ๋‚ด์šฉ : ${authDuplicateByUserIdDto.toString()}`);
        this.logger.log(`DB์— Select()๋ฌธ์„ ํ†ตํ•ด ํ•ด๋‹น ID๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!`);

        const { username } = authDuplicateByUserIdDto;

        this.logger.log(`username : ${username}`)

        const findByUserID = await this.findOne({
            where: { username : username}
        });

        this.logger.log(`DB์—์„œ ์กฐํšŒ๋œ ๊ฐ’ : ${findByUserID}`);

        if (findByUserID) {

            this.logger.log("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ID ์ž…๋‹ˆ๋‹ค! 409 Code์™€ ํ•จ๊ป˜ \"์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’ ์ž…๋‹ˆ๋‹ค!\" ๋ฐ˜ํ™˜ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!")

            return {
                statusCode: 409,
                messageKo: "์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’ ์ž…๋‹ˆ๋‹ค!",
                messageEn: "Conflict",
                data: findByUserID,
            };

        } else {

            this.logger.log("์ค‘๋ณต ๋˜๋Š” ๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค! 200 Code์™€ ํ•จ๊ป˜ \"์‚ฌ์šฉ ๊ฐ€๋Šฅ!\" ๋ฐ˜ํ™˜ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!");

            return {
                statusCode: 200,
                messageKo: "์‚ฌ์šฉ ๊ฐ€๋Šฅ!",
                messageEn: "OK",
                data: findByUserID,
            };
        } // if (findByUserID === null || findByUserID === undefined) ๋
    }   // duplicateUserID(authDuplicateByUserIdDto: AuthDuplicateByUserIdDto) ๋

DB์—์„œ ์กฐํšŒ๋œ ๊ฐ’์€ ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜ findByUserID์— ๋‹ด๊ธฐ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋’ค 49๋ฒˆ์งธ ์ค„์— DB์—์„œ ์กฐํšŒ๋œ ๊ฐ’์ด ์žˆ๋Š”์ง€ ํ™•์ธ์„ ํ•˜๋Š”๋ฐ, ์žˆ๋‹ค๋ฉด ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’์ด๋ผ๊ณ  ๋ฐ˜ํ™˜์„ ์ฃผ๊ณ , ์—†๋‹ค๋ฉด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋„๋ก ๊ตฌํ˜„์„ ํ•œ ๊ฒƒ์ด์—์š”.

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•œ ์ด์œ ๋Š” `Spring Boot` Project ๊ธฐ๋ฐ˜์— `Vue.js` Project์—์„œ `Spring Boot`์™€ ๋™์ผํ•˜๊ฒŒ API๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ์ธ ๊ฒƒ์ด์—์š”.

 

 

 

์ผ๋‹จ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด `Repository`์—์„œ ์‹ค์‹œํ•˜๊ณ , `Service`๋Š” ๋‹จ์ˆœํžˆ `Repository`์— ํ•ด๋‹น Method๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ํ•  ์ˆ˜ ๋ฐ–์— ์—†์—ˆ๋˜ ์ด์œ ๊ฐ€ DB์—์„œ ์กฐํšŒ๋œ ๊ฐ’์— ๋Œ€ํ•ด Null ๊ฐ’ ํ™•์ธ์„ ํ•ด์„œ ์žˆ๋Š”์ง€ ์—†๋Š”์ง€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•˜๋Š”๋ฐ,

`Service`์—์„œ ์ด Logic์„ ๊ตฌํ˜„ํ•˜๋ฉด `Repository`์—์„œ ๋„˜์–ด์˜จ ๊ฐ’์— ์ž๊พธ `Promise Object` ๊ฐ€ ๋‹ด๊ฒจ์„œ ์ „๋‹ฌ์ด ๋˜๋Š” ๊ฒƒ์ด์—์š”. DB์— ๊ฒฐ๊ณผ๊ฐ’์ด ์žˆ๋˜ ์—†๋˜์ง€์š”.

๊ทธ๋ž˜์„œ Optional์ฒ˜๋Ÿผ ๋ญ”๊ฐ€ ๋ณ€๊ฒฝํ•ด์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•˜๋Š”๊ฑด์ง€ ์•„๋‹ˆ๋ฉด Method๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ 3์‹œ๊ฐ„์ด ๋„˜๊ฒŒ ์ฐพ์•„๋ดค์ง€๋งŒ! ๐Ÿคฌ

์•ˆ๋‚˜์™€์„œ ์ผ๋‹จ ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด์—์š”.

 

 

auth.controller.ts

`Controller`๋Š” ๋‹จ์ˆœํžˆ `Service`๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , `Route` ๊ธฐ๋Šฅ์— ์ถฉ์‹คํ•˜๊ฒŒ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด์—์š”.

์ฃผ๋ชฉํ•ด์•ผ ํ•  ์ ์€ `Repository`์—์„œ result Object์— ๋ฐ˜ํ™˜ํ•  Data๋“ค์„ ๋‹ด์•˜์—ˆ๋Š”๋ฐ, ์ด ๋•Œ๋ฌธ์— ์ด ๊ณณ `Controller`์—์„œ๋Š” ๋ฐ˜ํ™˜์„ `Promise<any>`๋กœ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  ๊ฒฐ๊ณผ

Data Base user Table

๋ณด์‹œ๋ฉด ์•„์‹œ๊ฒ ์ง€๋งŒ, `TypeORM`, `Nest.js`์„ ์ฒ˜์Œ ์จ ๋ณด๋Š” ์ฃผ๋‹ˆํ•˜๋ž‘์€ ์—„์ฒญ๋‚˜๊ฒŒ ์‚ฝ์งˆ์„ ํ•œ ๊ฒƒ์ด์—์š”. ๐Ÿ˜ค

 

        ๐Ÿ“ฆ POSTMAN

DB์— ์กด์žฌํ•˜๋Š” Data๋ฅผ ์กฐํšŒํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ์ด๋ฏธ ์กด์žฌํ•œ๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

 

์ด๋ ‡๊ฒŒ Validation ์ฒ˜๋ฆฌ๋„ ์™„๋ฃŒ ํ•˜์˜€๊ตฌ์š”.

 

 

 

 

Data Base์— ํ•ด๋‹น ๊ฐ’์ด ์—†์œผ๋ฉด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

        ๐Ÿ“ฆ Vue.js

ID ์ค‘๋ณต ํ™•์ธ

 

 

 

๋ณ„๋ช… ์ค‘๋ณต ํ™•์ธ

 

 

 

Email ์ค‘๋ณต ํ™•์ธ

 

 

 

ํ•ธ๋“œํฐ ๋ฒˆํ˜ธ ์ค‘๋ณต ํ™•์ธ

 

 

 

ํšŒ์› ๊ฐ€์ž… ์™„๋ฃŒ

 

 

 

DB ์ •์ƒ ๋“ฑ๋ก ์™„๋ฃŒ (9๋ฒˆ์งธ)

 

 

 

 

๐Ÿš€ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”

์œ„์— Logic์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ์•„์ง ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™”ํ•ด์„œ DB์— ์ €์žฅํ•˜๋Š” Logic์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด์—์š”.

`Spring Boot`์—์„œ๋Š” `Spring Security`์˜ Interface ๊ฐ์ฒด์ธ `PasswordEncoder()`๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ, `Nest.js`์—์„œ๋Š” `bcryptjs`์„ ์ด์šฉํ•ด์„œ ํ•ด๋ณด๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

    ๐Ÿ”ฝ  ์„ค์น˜

        ๐Ÿ“ฆ bcryptjs

๋ช…๋ น์–ด

npm install bcryptjs --save

 

$npm install bcryptjs --save

 

์ด์šฉ์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‰๋ฌธ์œผ๋กœ ์ €์žฅ๋˜๋Š” ๊ฒƒ์€ ๋ง๋„ ์•ˆ๋˜๋Š” ๊ฒƒ์ด์—์š”.

๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™” ์—ด์‡ (Encryption Key)์™€ ํ•จ๊ป˜ ์•”ํ˜ธํ™”(์–‘๋ฐฉํ–ฅ)์œผ๋กœ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ, ์ด๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ์—์š”.

์–ด๋– ํ•œ ์•”ํ˜ธ๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™” ํ•˜๊ณ , ๊ทธ ์•”ํ˜ธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณตํ˜ธํ™”๋„ ๊ฐ€๋Šฅํ•œ ๊ฐœ๋…์ด ์–‘๋ฐฉํ–ฅ ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ธ ๊ฒƒ์ด์—์š”. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋Œ€๋ถ€๋ถ„ ์˜คํ”ˆ ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•”ํ˜ธํ™” ์—ด์‡ (Encryption Key)๊ฐ€ ์•…์˜์ ์ธ ์‚ฌ์šฉ์ž์—๊ฒŒ ํƒˆ์ทจ๋˜์–ด ๋ณตํ˜ธํ™”๊ฐ€ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์•„์ฃผ ๋†’์€ ๊ฒƒ์ด์—์š”.

 

์–‘๋ฐฉํ–ฅ ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜

 

๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ `Hash ์•Œ๊ณ ๋ฆฌ์ฆ˜`์„ ์ด์šฉํ•œ ๋‹จ๋ฐฉํ–ฅ ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์ด ๊ฐœ๋…์€ ํ•œ๋ฒˆ ์•”ํ˜ธํ™”๊ฐ€ ๋˜๋ฉด ๋ณตํ˜ธํ™”๋ฅผ ํ•  ์ˆ˜ ์—†๋„๋ก ๋งŒ๋“œ๋Š” ๊ฐœ๋…์ธ ๊ฒƒ์ด์—์š”.

๋Œ€ํ‘œ์ ์œผ๋กœ ์ด์šฉ๋˜๋Š” ๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์šด์˜์ฒด์ œ(Linux, Window)์— ๊ณ„์ •์„ ๋งŒ๋“ค ๋•Œ์™€ Login ํ•  ๋•Œ ์ด์šฉ๋˜๋Š” ๊ฒƒ์ด์—์š”.

`Hash ์•Œ๊ณ ๋ฆฌ์ฆ˜`์€ `Rainbow Table Attack`์œผ๋กœ ์•”ํ˜ธํ™” ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณต๊ฒฉ์„ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋Œ€๋ถ€๋ถ„ ์ด์šฉ์ž๋“ค์€ ๊ฑฐ์˜ ๋น„์Šทํ•œ ์•”ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋งˆ๋ จ์ด์—์š”. `A ์ด์šฉ์ž`, `B ์ด์šฉ์ž`๊ฐ€ ๋‘˜ ๋‹ค 1234๋ผ๋Š” ์•”ํ˜ธ๋ฅผ ์ด์šฉํ•  ๋•Œ, `Hash` ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด ์•”ํ˜ธํ™”๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด ๋™์ผํ•œ ์•”ํ˜ธ๊ฐ’์ด ๋‚˜์˜ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐœ๋…์ด ์†Œ๊ธˆ์˜ ์˜์–ด ๋‹จ์–ด `salt`์™€ ํ‰๋ฌธ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•ฉ์นœ ๋’ค์— Hash ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ํ•จ๊ป˜ ์•”ํ˜ธํ™”๋ฅผ ํ•˜์—ฌ ๋™์ผํ•œ ํ‰๋ฌธ๊ฐ’์„ ์ž…๋ ฅํ•ด๋„ ๋‹ค๋ฅธ ๊ฐ’์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์œ„์—์„œ ์ด์•ผ๊ธฐ ํ–ˆ๋˜ ์šด์˜์ฒด์ œ๋Š” ์ด `salt`๋ฅผ ์ด์šฉํ•ด์„œ ์•”ํ˜ธํ™”๋ฅผ ํ•˜๊ณ  ์žˆ๋‹ต๋‹ˆ๋‹ค! 

`bcryptjs`๋Š” ์œ„์—์„œ ์ด์•ผ๊ธฐํ•œ `Hash` ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ `salt` ๊ฐœ๋…์„ ์ด์šฉํ•œ ์•”ํ˜ธํ™” ์ง€์› Module์ธ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  ๊ตฌํ˜„ํ•˜๊ธฐ

auth.repository.ts - 1 ~ 24

์ตœ์ดˆ 9๋ฒˆ์งธ ์ค„์ฒ˜๋Ÿผ `bcryptjs` Module์„ `Import` ํ•ด์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

auth.repository.ts - signUp()

230๋ฒˆ์งธ ์ค„์„ ๋ณด๋ฉด `bcrypt Module`์•ˆ์— `genSalt()`๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ Salt๊ฐ’์„ ๋งŒ๋“  ๋’ค ์ด๋ฅผ ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜ `salt`์— ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋’ค 235๋ฒˆ์งธ ์ค„์— `bcrypt Module`์•ˆ์— `hash()`๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ์ด์šฉ์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ `salt` ๊ฐ’์„ ๊ฐ™์ด ์ „๋‹ฌํ•ด์ฃผ์–ด `Hash ์•”ํ˜ธํ™”`๊ฐ€ ์ง„ํ–‰ ๋˜๋„๋ก ํ•ด ์ค€ ๊ฒƒ์ด๊ณ , ๊ทธ ๊ฐ’์„ ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜ `hashPassword`์— ๋„ฃ์–ด ์ค€ ๊ฒƒ์ด์—์š”.

240๋ฒˆ์งธ ์ค„์— ์ƒ์ˆ˜ํ˜• ๋ณ€์ˆ˜ `user`์— ์ด์šฉ์ž๊ฐ€ ํšŒ์› ๊ฐ€์ž… ์‹œ ์ž…๋ ฅํ–ˆ๋˜ ๊ฐ’๋“ค์„ ๊ฐ€์ง€๊ณ  ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋Š”๋ฐ, ์ด๋•Œ ์ด์šฉ์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธํ™” ์•”ํ˜ธํ™” ๋˜๋„๋ก ์„ค์ •ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  ๊ฒฐ๊ณผ

        ๐Ÿ“ฆ POSTMAN

Postman Test

 

DB User Table

์ •์ƒ์ ์œผ๋กœ ๊ฐ’์ด ๋“ค์–ด๊ฐ„ ๊ฒƒ์ด์—์š”.

 

 

        ๐Ÿ“ฆ Vue.js

ํšŒ์›๊ฐ€์ž… ๋ฒ„ํŠผ ๋ˆ„๋ฅด๊ธฐ ์ „

 

ํšŒ์› ๊ฐ€์ž… ๋ฒ„ํŠผ ๋ˆ„๋ฅธ ๋’ค Console.log ๋‚ด์šฉ

 

 

DB User Table

Vue.js๋ฅผ ํ†ตํ•ด์„œ๋„ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ ๋˜๋Š” ๊ฒƒ์ด์—์š”!

 

 

๐Ÿ’ก ์ฐธ๊ณ  ์‚ฌํ•ญ

๊ทธ๋ž˜์„œ ์•ˆ์ „ํ• ๊นŒ?

์œ„์— ๋ฐฉ๋ฒ•์€ ์™„์ „ํ•˜๊ฒŒ ์•ˆ์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ทธ ์ด์œ ๋Š” Client์—์„œ Server์—๊ฒŒ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ, ํ‰๋ฌธ๊ฐ’์œผ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ „๋‹ฌ๋˜๊ธฐ ๋•Œ๋ฌธ ์ž…๋‹ˆ๋‹ค.
์•…์˜์ ์ธ ์ด์šฉ์ž๊ฐ€ Man in the Middle Attack(์ค‘๊ฐ„์ž ๊ณต๊ฒฉ)์„ ํ†ตํ•ด ํƒˆ์ทจ๋ฅผ ํ•˜๊ฑฐ๋‚˜, Sniping์„ ํ†ตํ•ด ๋„์ฒญ์„ ํ•˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‰ฝ๊ฒŒ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋ž˜์„œ ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ SSL/TLS๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด๊ณ , ์ง€๊ธˆ ์ฃผ๋‹ˆํ•˜๋ž‘ Blog ์ฃผ์†Œ์ฐฝ์„ ๋ณด์‹œ๋ฉด https://๋กœ ์‹œ์ž‘๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

 

 

 

 

๋‹ค์Œ ํฌ์ŠคํŒ…์€ Login ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ๊ณต๋ถ€ํ•ด ๋ณด๋„๋ก ํ•  ๊ฒƒ์ด์—์š”.

 

 

 

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

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

 

 

 

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•