✅ JWT, passport 모듈 추가
npm i @nestjs/jwt @nestjs/passport passport passport-jwt --save
✔ @nestjs/jwt - nest에서 jwt를 사용하기 위한 모듈
✔ @nestjs/passport - nest에서 passport를 사용하기 위한 모듈
✔ passport - passport 모듈
✔ passport-jwt - passport와 jwt를 연동하기 위한 모듈
📝./src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { UserRepository } from './user.repository';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: 'MySecretKey1234',
signOptions: {
expiresIn: 3600,
},
}),
TypeOrmModule.forFeature([UserRepository]),
],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}
passport는 PassportModule.register로 등록
✔ defaultStrategy - 전략 지정, 여기서는 jwt를 이용한 로그인이니까 jwt로 지정
jwt는 JwtModule.register 로 등록하면 됨
✔ secret - secret key를 지정한다
✔ signOptions.expiresIn - 토큰 만료 기간을 지정, 3600은 한 시간
📝./src/auth/auth.service.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AuthCredentialDto } from './dto/auth-credential.dto';
import { UserRepository } from './user.repository';
import * as bcrypt from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(
@InjectRepository(UserRepository)
private userRepository: UserRepository,
private jwtService: JwtService,
) {}
async signUp(authCredentialDto: AuthCredentialDto): Promise<void> {
return this.userRepository.createUser(authCredentialDto);
}
async signIn(
authCredentialDto: AuthCredentialDto,
): Promise<{ accessToken: string }> {
const { username, password } = authCredentialDto;
const user = await this.userRepository.findOne({ username });
if (user && (await bcrypt.compare(password, user.password))) {
//유저 토큰 생성 (Secret + Payload 필요)
const payload = { username };
const accessToken = await this.jwtService.sign(payload);
return { accessToken };
} else {
throw new UnauthorizedException('Login Failed');
}
}
}
JwtService에 대한 의존성 주입 이후
리턴 값으로 accessToken을 객체로 감싸서 반환
여기서 payload 에 간단한 정보를 담아서 서명할 수 있다
(중요한 정보는 절대 담지 않도록 주의)
✅ 토큰 인증 기능 구현
npm i @types/passport-jwt --save
타입스크립트에서 passport, jwt 를 위한 타입을 사용하기 위한 모듈
📝./src/auth/jwt.strategy.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
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: 'MySecretKey1234',
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
});
}
async validate(payload) {
const { username } = payload;
const user: User = await this.userRepository.findOne({ username });
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
JWT Strategy 는 PassportStrategy 를 상속받아서 구현한다
생성자에서는 DB와의 연동을 위해 userRepository 주입
또한 부모인 PassportStrategy 의 생성자를 통해 비밀 키와 토큰 타입을 지정해준다
아까 생성할때 사용한 비밀키와 똑같이 넣고
여기서는 BearerToken 을 사용하기 떄문에 그렇게 주입
📝./src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './jwt.strategy';
import { UserRepository } from './user.repository';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: 'MySecretKey1234',
signOptions: {
expiresIn: 3600,
},
}),
TypeOrmModule.forFeature([UserRepository]),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [JwtStrategy, PassportModule],
})
export class AuthModule {}
auth module 외부에서도 사용할 수 있게 하기 위해서
JwtStrategy 와 PassportModule 을 export 해줌
provider 에 JwtStrategy 도 등록해준다
📝./src/auth/auth.controller.ts
@Post('/test')
@UseGuards(AuthGuard())
test(@Req() req) {
console.log('req', req);
}
@UseGuards 를 통해 인증 처리를 해줄 수 있다
Pipe 와 마찬가지 처럼 Guard 도 미들웨어로서 동작한다
인증과 관련된 것이기 때문에 AuthGuard() 를 주입해준다
Guard를 주입하지 않으면 인증 처리가 제대로 동작하지 않음
✅ req.user 바로 가져오기 - 커스텀 데코레이터 생성
📝./src/auth/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;
},
);
createParamDecorator를 통해 파라미터 레벨의 데코레이터를 만들 수 있다
인자로 함수를 넣는데 ctx 부분을 ExecutionContext 로 지정해주면 된다
request를 받아서 반환하면 req.user를 즉시 반환 가능
⚠ 단, request 에 user가 있다는 전제 하에만 사용해야 한다
📝./src/auth/auth.controller.ts
@Post('/test')
@UseGuards(AuthGuard())
test(@GetUser() user: User) {
console.log('user', user);
}
확실히 req.user 를 가져오는 것 보다 깔끔해지긴 한다
'📡 백엔드 > 🐱 Nest.js' 카테고리의 다른 글
[NestJs] 따라하면서 배우는 NestJs - 9 (로그, 설정) (0) | 2022.07.09 |
---|---|
[NestJs] 따라하면서 배우는 NestJs - 8 (권한 부여, 유저와 게시글 관계 부여) (0) | 2022.07.09 |
[NestJs] 따라하면서 배우는 NestJs - 6 (auth 모듈 구현) (0) | 2022.07.07 |
[NestJs] 따라하면서 배우는 NestJs - 5 (레포지토리 구현 및 DB 이용 CRUD) (0) | 2022.07.07 |
[NestJs] TypeORM 사용 시 RepositoryNotFoundError 해결하기 (0) | 2022.07.06 |