이번에 로그인 기능을 구현해 볼 기회가 생겨서 작업한 것을 정리해보려 한다.
먼저 server 단에서 구현한 부분에 대해 작성할 것이다. 사실 client 측은 별게 없어서 안해도 될 거 같다.
(사용 스펙 : node.js, NestJS, JWT, passport, typeScript, typeORM)
전체적으로 구현한 것을 보면 jwt를 사용해 로그인 시 accessToken을 생성해 쿠키에 저장해 두고 로그인 상태를 관리할 수 있도록 구현했고, 로그인 상태에 따라 api 호출에 제한을 주기 위해 passport를 사용했다.
해당 기능을 개발하기 위해 추가한 라이브러리이다.
npm install 명령어를 통해 추가하면 된다.
"@nestjs/jwt": "^7.2.0",
"@nestjs/passport": "^7.1.5",
"bcrypt": "^5.0.1",
"cookie-parser": "^1.4.5",
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
먼저 로그인 api 호출시 유저가 정상적으로 로그인할 수 있는 상태인지 확인해주는 LocalStrategy를 구현한 것에 대해 정리해보려 한다.
/local.strategy.ts
import { PassportStrategy } from '@nestjs/passport';
import { AuthService } from '../services/auth.service';
import { Strategy } from 'passport-local';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { JwtPayload } from './jwt.payload';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: false,
});
}
async validate(email: string, password: string) {
const payload: JwtPayload = { email, password };
const user = await this.authService.validateAccount(payload);
if (!user) {
throw new HttpException('Invalid token', HttpStatus.UNAUTHORIZED);
}
return user;
}
}
validate 메서드가 로그인 api 실행 이전에 먼저 실행되어 해당 유저의 상태를 검사해주는 역할을 해줄 것이다.
주의할 점은 기본적으로 username 과 password 필드로 설정이 되어있기 때문에 username 이 아닌 email 필드로 검사하고 싶다면 contructor에 위와 같이 usernameField: 'email' 을 설정해줘야 한다는 것이다.
LocalStrategy를 로그인 api 실행 이전에 먼저 실행되도록 하고 싶다면 로그인 api에 @UseGuards() 어노테이션을 추가해주면 된다.
/user.controller.ts
@UseGuards(AuthGuard('local'))
@Post('/User/Login')
public async login(@Body() dto: LoginUserDto, @Res() res: Response) {
this.authService
.login(dto)
.then((result) => {
res
.status(HttpStatus.OK)
.json(ResponseBody.createResponseBody().setBody(result));
})
.catch((e) => {
console.log(e);
res
.status(HttpStatus.OK)
.json(
ResponseBody.createResponseBody()
.setResultCode(RESULT_CODE.ERROR_BUT_IGNORED)
.setErrorCode(ERROR_CODE.DB_DATA_NOT_FOUND)
.setErrorDesc(e),
);
});
}
사용할 전략이 LocalStrategy 이기 때문에 @UseGuards(AuthGuard('local')) 을 추가해주면 /User/Login api 호출 시 AuthGuard 가 먼저 실행된다.
/user.dto.ts
export class LoginUserDto {
email: string;
password: string;
}
모듈을 추가해줌으로 사용 가능하게 해 준다.
/auth.module.ts
import { Module } from '@nestjs/common';
import { UserController } from '../controllers/user.controller';
import { AuthService } from '../services/auth.service';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from '../jwt/local.strategy';
@Module({
imports: [
PassportModule,
],
controllers: [UserController],
providers: [AuthService, LocalStrategy],
})
export class AuthModule {}
/auth.service.ts
LocalStrategy에서 validate 메서드에서 실행되는 validateAccount의 내용이다.
async validateAccount(payload: JwtPayload) {
const user: User = await this.userService.findByLogin(payload);
if (user) {
const { password, ...result } = user;
return result;
}
return null;
}
email과 password 정보로 db에서 유저를 찾고, 그 유저가 존재한다면 유저의 정보를 리턴하도록 구현했다.
(당연히 findByLogin()에 bcrypt로 암호화된 password와 파람으로 넘어온 password를 비교하여 검사하는 부분 존재)
다음 글 : [NestJS / JWT / Passport] 로그인 2. JWTStrategy
'Node.js > nest.js' 카테고리의 다른 글
[NestJS / JWT / Passport] 로그인 2. JWTStrategy (2) | 2021.04.28 |
---|