Skip to content

Local Guard

이번에는 passport를 이용해서 로그인을 인증하는 과정을 해보도록 하겠습니다!
NestJs Passport
Github Link

기본개념

  • 인증: 사용자의 자격 증명(예: 사용자 이름/비밀번호, JWT)을 검증하는 과정입니다.
  • 상태 관리: 인증된 사용자에 대한 정보를 관리하고, 이를 통해 인증된 사용자의 요청을 처리합니다.
  • 전략(Strategy): 다양한 인증 메커니즘을 구현하기 위한 방법입니다. Passport는 다양한 전략을 지원합니다.

필요한 패키지 설치

sh
npm install --save @nestjs/passport passport passport-local
npm install --save-dev @types/passport-local

passport를 이용한 Login 구현

lib - auth 폴더에 local 폴더를 만들고 두개의 파일을 만듭니다.

local.strategy.ts

typescript
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, "local") {
  // default passport name: 'local'
  constructor(private readonly loginService: LoginService) {
    super({
      usernameField: "username", // default: 'username'
      passwordField: "password", // default: 'password'
    });
  }

  validate(username: string, password: string) {
    return this.loginService.login(username, password);
  }
}

여기서 validate의 method에서 return된 값은 requst.user로 들어게 됩니다.

local.guard.ts

typescript
@Injectable()
export class LocalAuthGuard extends AuthGuard("local") {}

login 만들기

cli

sh
nest g mo login
nest g s login --no-spec
nest g co login --no-spec

login controller

typescript
@ApiTags("login")
@Controller("login")
export class LoginController {
  @UseGuards(LocalAuthGuard)
  @Post()
  async login(@Req() req: Request) {
    return req.user;
  }
}

login service

typescript
@Injectable()
export class LoginService {
  private readonly users: UsersDto[] = [
    {
      id: 1,
      username: "atreides",
      password: "12",
    },
    {
      id: 2,
      username: "harkonnen",
      password: "23",
    },
    {
      id: 3,
      username: "Fremen",
      password: "34",
    },
    {
      id: 4,
      username: "Corrino",
      password: "45",
    },
  ];

  login(username: string, password: string): UsersDto {
    const findUser = this.users.find((user) => user.username === username);

    if (!findUser) {
      throw new BadRequestException("사용자를 찾을 수 없습니다.");
    }

    if (findUser.password !== password) {
      throw new UnauthorizedException("비밀번호가 일치하지 않습니다.");
    }

    return new UsersDto(findUser);
  }
}

Nestjs에서는 다양한 경우의 excpeiton class를 제공합니다.
Exception Class

login dto

typescript
export class UsersDto {
  id: number;

  @IsNotEmpty()
  @IsString()
  username: string;

  @Exclude() // 이 부분을 적용하여 제외시킵니다.
  @IsNotEmpty()
  @IsNumberString()
  password: string;

  constructor(partial: Partial<UsersDto>) {
    Object.assign(this, partial);
  }
}

login module

typescript
@Module({
  controllers: [LoginController],
  providers: [LoginService],
  exports: [LoginService],
})
export class LoginModule {}

실행

저는 vscode의 Thunder Client를 이용해서 http:localhost:3000/api/login으로 post 요청을 해보겠습니다.
그럼 아래와 같이 request에 비밀번호가 빠진 user 정보를 받게 됩니다. alt
비밀번호가 틀렸다면 아래와 같이 에러가 발생됩니다. alt
아이디가 없다면 아래와 같은 에러가 발생합니다. alt

다음..

다음으로는 cookie에 jwt(Json Web Token)을 넣어보는 과정을 해보도록 하죠!
그래서 메뉴를 준비과정에 있던 Cookie Parser로 가봅시다~