로그인을 할 때 그 로그인한 고유 유저를 위한 토큰을 생성해야 하는데 그 토큰을 생성할 때 JWT라는 모듈을 사용

Header
Payload
Verify Signature

payload + Verify Signature의 secret key를 해시 알고리즘을 통해 생성한다.
jwt 모듈과 passport 모듈을 함께 사용해서 토큰 생성passport는 jwt를 이용하여 인증 처리하는 과정을 쉽게 만들어줌모듈 생성 @nestjs/jwt @nestjs/passport passport passport-jwt
npm install @nestjs/jwt @nestjs/passport passport passport-jwt --save
auth.module.ts
JwtModule.register({
secret: 'Secret1234',
signOptions: {
expiresIn: 60 * 60,
},
}),
auth.module.ts
PassportModule.register({ defaultStrategy: 'jwt' }),

auth.service.tsprivate jwtService: JwtService,

Token을 만드려면 Secret과 Payload가 필요
Payload에는 자신이 전달하고자 하는 정보를 넣어줌
ex) Role, 유저 이름, 이메일....단, 민감한 정보는 넣으면 안됨
Payload를 이용해서 JWT에서 토큰을 만들 때 사용하는 Sign 메소드를 이용해서 토큰을 생성
async signIn(
authCredentialsDto: AuthCredentialsDto,
): Promise<{ accessToken: string }> // 추가
// 유저 토큰 생성 (Secret + Payload)
const payload = { username };
const accessToken = await this.jwtService.sign(payload);
return { accessToken };

auth.controller.ts
@Post('/signin')
signIn(
@Body(ValidationPipe) authCredentialsDto: AuthCredentialsDto,
): Promise<{ accessToken: string }> { // 추가
return this.authService.signIn(authCredentialsDto);
}

1-4번=> 지난 시간 /5-6번=> 오늘 해야할 부분

auth.controller.ts
@Post('/signin')
signIn(
@Body(ValidationPipe) authCredentialsDto: AuthCredentialsDto,
): Promise<{ accessToken: string }> {
return this.authService.signIn(authCredentialsDto);
}
auth.service.ts
const accessToken = await this.jwtService.sign(payload);
auth.service.ts
return { accessToken };

i)
서버에서 그 토큰이 유효(valid)한 것인지 체크
ii)
만약 유효한 것이면payload안에 들어있는username을 이용해서 데이터베이스에 있는 유저인지 체크
iii)
있는 유저라면 유저 객체를 데이터베이스에서 가져오고, 없는 유저라면 에러를 보냄
@types/passport-jwtnpm i @types/passport-jwt --save
jwt.strategy.ts 파일 생성import { Injectable } from '@nestjs/common';
import { UnauthorizedException } from '@nestjs/common/exceptions';
import { PassportStrategy } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { User } from './user.entity';
import { UserRepository } from './user.repository';
@Injectable() // 어디에서나 주입해서 사용 가능하게 하기 위함
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
@InjectRepository(UserRepository)
private userRepository: UserRepository,
) {
super({
// 부모 컨포넌츠를 사용하기 위함
secretOrKey: 'Secret1234', // 토큰이 유효한지 체크, authmodule에 있는 값과 같음
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
// 토큰을 어디서 가져와서 검증을 하는지
// bearer 토큰 타입으로 가져옴
});
}
// 인증 성공 후
async validate(payload) {
// 토큰에 payload가 들어옴
const { username } = payload;
const user: User = await this.userRepository.findOneBy({ username });
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
@Injectable() : 어디에서나 주입해서 사용 가능하게 하기 위함super : 부모 컨포넌츠를 사용하기 위함secretOrKey: 'Secret1234'jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()auth.module.tsproviders: [AuthService, JwtStrategy],
exports: [JwtStrategy, PassportModule],
providers: [AuthService, JwtStrategy]exports: [JwtStrategy, PassportModule]auth.controller.ts
@Post('/test')
test(@Req() req) {
console.log('req', req);
}
결과 ===> 실패
UseGuards 미들웨어 사용UseGuards안에 @nestjs/passport에서 가져온 AuthGuard()를 이용하면 요청안에 유저 정보를 넣어줄 수 있다. @Post('/test')
@UseGuards(AuthGuard())
test(@Req() req) {
console.log('req', req);
}

Nest JS에는 여러가지 미들웨어가 있다.
(Pipes, Filters, Guards, Interceptors 등)
각각의 미들웨어가 불러지는(called) 순서
middleware -> guard -> interceptor (before) -> pipe
-> controller -> service -> controller -> interceptor (after)
-> filter (if applicable) -> client
req.user가 아닌 바로 user 라는 파라미터로 가져올 수 있다.get-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { User } from './user.entity';
export const GetUser = createParamDecorator(
(data, ctx: ExecutionContext): User => {
const req = ctx.switchToHttp().getRequest();
return req.user;
},
);
auth.controller.ts
@Post('/test')
@UseGuards(AuthGuard())
test(@GetUser() user: User) {
console.log('user', user);
}

board 모듈에서 쓸 수 있어야 하기에 boardmodule에서 인증 모듈 imports 해오기authmodule에서 export 하는 어떠한 것이든 boardmodule에서 사용 가능board.module.ts
@Module({
imports: [
TypeOrmExModule.forCustomRepository([BoardRepository]),
AuthModule // 추가
],
UseGuards(AuthGuard()) 를 이용해서 이 사람이 요청을 줄 때 올바른 토큰을 가지고 요청을 주는지 본 후에 게시물에 접근 할 권한을 줌
AuthGuard는 각각의 라우트 별로 줄 수도 있고 한번에 하나의 컨트롤러 안에 들어있는 모든 라우트에 줄 수도 있다.
현재는 board 컨트롤러 안에 있는 모든 라우트에 AuthGuard를 적용
board.controller.ts
@Controller('boards')
@UseGuards(AuthGuard()) // 추가
