4. 보안과 인증(Local / JWT)

Eden·2023년 7월 30일
0

보안과 인증
Passport
passport는 미들웨어를 구현하기 위한 패키지로 간단하고 유연한 방식으로 사용자 인증을 관리하고 처리할 수 있도록 도와주며, 다양한 인증 전략(Strategy)을 제공하여 여러 인증 방식을 지원

사용자 인증 방식으로는 로컬(Username/Password), 소셜 로그인(Google, Facebook, Twitter 등), OAuth, JWT(JSON Web Token) 등 다양한 방법을 Passport를 통해 구현가능

1.local 인증

패키지 설치

npm install @nestjs/passport passport @types/passport-local passport-local @types/express

@nestjs/passport: NestJS에서 Passport를 사용하기 위한 모듈. NestJS와 Passport를 연결해주는 역할

passport: Passport 패키지

@types/passport-local: Passport 패키지를 TypeScript로 사용하기 위한 타입 선언 파일.

passport-local: 로컬 인증(Local Authentication) 전략을 제공하는 Passport의 전략(strategy) 중 하나.

@types/express: Express.js를 TypeScript로 사용하기 위한 타입 선언 파일.

다음으로 local-auth.strategy.ts 파일을 만든다

@Injectable()
export class LocalAuthStrategy extends PassportStrategy(Strategy){
  constructor(
  	private authService: AuthService;
  ){
    super({ usernameField : 'email' } //상위 클래스(PassportStrategy)의 생성자를 호출
  }
  
          
// PassportStrategy를 상속받은 커스텀 전략에서 반드시 구현해야 하는 validate 메서드. 
// 사용자의 인증을 수행하는 로직을 구현
  async validate( email:string, password: string ): Promise<User>{
    return await this.authService.userLogin({ email, password });
  }
}

생성된 strategy class를 auth.module provider 에 추가한다.

인증과 관련된 로직을 미들웨어로 분리하여 코드를 구조화하고 중복을 제거하기 위해 local-auth.guard.ts 파일도 생성해준다.

@Injectable()
export class LocalAuthGuard extends AuthGuard('local'){}
// AuthGuard 생성자에서 사용할 Strategy를 인자로 넘겨줌으로 LoaclAuthStrategy에 구현한 로직이 반영된다.

적용
auth.controller 에 strategy를 적용
인증을 사용할 api 매소드에 다음과 같이 추가해준다.

 @Post('login')
 @UseGuards(LocalAuthGuard)
 async  userLogin(
    @Body()
    loginUserDto:LoginUserDto
  ){
    return await this.authService.userLogin(loginUserDto);
 }

2.토큰생성
토큰 생성에는 JWT( JSON Web Token 웹 표준(RFC 7519)으로서, 정보를 안전하게 전달하기 위해 JSON 형식을 사용하는 토큰)을 사용

패키지 설치

npm install @nestjs/jwt passport-jwt @types/passport-jwt cookie-parser @types/cookie-parser

@nestjs/jwt: NestJS 애플리케이션에서 JWT(JSON Web Token) 인증을 구현하기 위한 패키지

passport-jwt: PassportJS를 사용하여 JWT 인증 전략을 구현하는 패키지

@types/passport-jwt: TypeScript를 사용하는 경우, passport-jwt 패키지의 타입 정의를 제공

cookie-parser: HTTP 요청에서 쿠키를 파싱하여 사용할 수 있게 해주는 미들웨어 패키지

@types/cookie-parser: TypeScript를 사용하는 경우, cookie-parser 패키지의 타입 정의를 제공

패키지 설치가 끝나면 auth.module에 ConfigModule(.env에 토큰관련 값을 저장/관리해야함), PassportModule, JwtModule.register({}) 를 import 시킨다.

토큰값은 민감한 정보이기 때문에 전에 생성해놓은 .env 파일에 추가한다

JWT_ACCESS_TOKEN_SECRET= xxx
JWT_ACCESS_TOKEN_EXPIRATION_TIME=10

app.module에 ConfigModule 유효성검사 부분에 추가한 항목도 반영해주어야함

-토큰 생성

//tokenPayload.interface.ts 파일생성 (토큰에 담기는 데이터)
export interface TokenPayload{
  userId:string;
}
//

//토큰 생성 함수 (auth.service.ts)
+
//생성자에 jwtService 와 configService를 선언해주어야함
async generateToken(userId:string):Promise<string>{
  const payload: TokenPayload = { userId }; //jwt.Service.sign에 넘겨줄 인자
  const token = this.jwtService.sign(payload,{
    secret : this.configService.get('JWT_ACCESS_TOKEN_SECRET'),// 토큰을 암호화 하는데 필요한 비밀키
    expiresIn : `${this.configService.get('JWT_ACCESS_TOKEN_EXPIRATION_TIME')}h`//뒤에 h는 시간단위를 의미
  });
  return token;
}

-토큰으로 유저 조회

jwt-auth.guard.ts/jwt-auth.strategy.ts 생성

@Injectable()
export class JwtAuthStrategy extends PassportStrategy(Strategy){
  constructor(
    private readonly userService: UserService,
    private readonly configService: ConfigService,
  ){
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),//클라이언트에서 서버로 전송된 JWT 토큰을 어떻게 추출할지를 지정
      secretOrkey: configService.get('JWT_ACCESS_TOKEN_SECRET')//토큰의 유효성을 검증하는데 사용되는 비밀키(secret key)를 지정
    });
  }
  async validate(payload: TokenPayload): Promise<User>{
    return await this.userService.getUserById(payload.userId)
  }
}


@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt'){}

-requestWithUser.interface.ts 파일 생성
기존 Request에서 요청 객체를 확장(+User 클래스)하여 사용하기 위해

export interface RequestWithUser extends Request {
  user: User;
}

-api method 생성
auth.controller.ts에 다음 함수 추가

+
@Get()
@UseGuards(JwtAuthGuard)
async authedUser(
  @Req()
  req: RequestWithUser
  ){
  const user = req.user;
  return user;
}
	


profile
주섬주섬..

0개의 댓글