2022. 4. 11. 22:18ใProgramming Project ์์ ์ค/๋ด์ฉ ์ ๋ฆฌ
Project Git Hub
๐ ๋ชฉ์ฐจ
โ [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - ํ์ ๊ฐ์
โ [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - JWT๋ฅผ ์ด์ฉํ Login
โ [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - Custom Decorator
๐ ๋ถ๋ก
โ [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์ธ ๊ฒ์ด์์.
์ฃผ๋ํ๋์ ์ง๋ ํฌ์คํ ์์ 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
๐ฝ ์ด๊ธฐ ๊ตฌ์ฑ
๐ฆ 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 ๋ฑ๋ก
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`์ธ๋ฐ, ์ด์ ๋ํ ๋ด์ฉ์ `์ด ๊ณณ`์ ์ค๋น ํด ๋๊ฒ์.
๐ฝ ๊ฒฐ๊ณผ
๋จผ์ Test๋ฅผ ์ํ Route Method๋ฅผ ํ๋ ๋ง๋ค์ด ์ค ๊ฒ์ด์์.
๐ฆ 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์ ์ถ๋ ฅ๋ ๊ฒฐ๊ณผ์ธ ๊ฒ์ด์์.
์์ ๊ฐ์ด ์ ์์ ์ผ๋ก ํ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ ๊ฒ์ด์์.
์ด ๊ณณ์ ๋ณด๋ฉด ํ์์ ๋น๋ฐ๋ฒํธ๊ฐ ๋ ธ์ถ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์. ์๋ฌด๋ฆฌ ์ํธํ๊ฐ ๋์ด ์๋ค๊ณ ํด๋ ํ์์๋ ๊ฐ์ด ์ค๊ณ ๊ฐ๋๊ฑธ ์ฃผ๋ํ๋์ ์์น ์๋ ๊ฒ์ด์์.
์ด๋ฅผ ๋ง๊ธฐ ์ํด ์ ๊ทธ๋ฆผ์์ 47 ~ 49๋ฒ์งธ ์ค์ DB ์กฐํ ๋ถ๋ถ์์ `select` Option์ ํตํด ํ์ ๊ณ ์ ๋ฒํธ, ํ์ ID, ํ์ Email์ฃผ์๋ง ์กฐํํด์ ๊ฐ์ ธ์ค๋๋ก ์ถ๊ฐ ํด ์ค ๊ฒ์ด์์.
์ด์ ์์น ์๋ ๊ฐ์ ์ ์ธํ๊ณ , ์ํ๋ ๊ฐ๋ง ์ป์ด์ค๋ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์.
์ด์ ๊ธ : [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - JWT๋ฅผ ์ด์ฉํ Login
๋ค์ ๊ธ : [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - Custom Decorator