NestJs LogIn

까망거북·2024년 10월 28일

로그인 기능

참고 자료

설치

npm i @nestjs/jwt

파일 작성

  • User 생성

    nest g res user ↵
    REST API 선택
    Would you like to generate CRUD entry points? (Y/n) N 입력

  • 파일 생성 확인

    • src/user/user.controller.ts
    • src/user/user.module.ts
    • src/user/user.service.ts
  • 수정

    • user.module.ts
    import { Module } from '@nestjs/common';
    import { UsersService } from './users.service';
    import { UsersController } from './users.controller';
    
    @Module({
      controllers: [UsersController],
      providers: [UsersService],
      exports: [UsersService], +
    })
    export class UsersModule {}
    • user.service.ts
    import { Injectable } from '@nestjs/common';
    
    export type User = any;
    @Injectable()
    export class UsersService {
      private users = [
        {
          id: 1,
          username: 'jjjj',
          password: '111111',
        },
        {
          id: 2,
          username: 'dddd',
          password: '222222',
        },
      ];
    
      async findOne(username: string): Promise<User | undefined> {
        return this.users.find((user) => user.username === username);
      }
    
      async findAll(): Promise<User[]> {
        return this.users;
      }
    }
    
  • Auth 생성

    nest g res auth ↵
    REST API 선택
    Would you like to generate CRUD entry points? (Y/n) N 입력

  • 파일 생성 확인

    • src/auth/auth.controller.ts
    • src/auth/auth.module.ts
    • src/auth/auth.service.ts
  • 수정

    • auth.module.ts
    import { Module } from '@nestjs/common';
    import { AuthService } from './auth.service';
    import { AuthController } from './auth.controller';
    import { UsersModule } from 'src/users/users.module';
    import { JwtModule } from '@nestjs/jwt';
    import { jwtConstants } from './constants';
    
    @Module({
      imports: [
        UsersModule,
        JwtModule.register({
          global: true,
          secret: jwtConstants.secret,
          signOptions: { expiresIn: '1h' },
        }),
      ],
      providers: [AuthService],
      controllers: [AuthController],
      exports: [AuthService],
    })
    export class AuthModule {}
    
    • auth.controller.ts
    import {
      Controller,
      HttpStatus,
      Body,
      HttpCode,
      Post,
      Request,
      UseGuards,
      Get,
    } from '@nestjs/common';
    import { AuthService } from './auth.service';
    import { SignInDto } from './dto/SignInDto';
    import { Public } from 'src/util/public.meta';
    
    @Controller('auth')
    export class AuthController {
      constructor(private readonly authService: AuthService) {}
    
      @HttpCode(HttpStatus.OK)
      @Public()
      @Post('login')
      async signIn(@Body() signInDto: SignInDto) {
        return this.authService.signIn(signInDto.username, signInDto.password);
      }
    
      @Get('profile')
      getProfile(@Request() req) {
        return 'authenticated success';
      }
    
      @Public()
      @Get('all')
      finaAll() {
        return 'not authenticated';
      }
    }
    
    • auth.service.ts
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { UsersService } from '../users/users.service';
    import { JwtService } from '@nestjs/jwt';
    
    @Injectable()
    export class AuthService {
      constructor(
        private readonly usersService: UsersService,
        private readonly jwtService: JwtService,
      ) {}
    
      async signIn(
        username: string,
        password: string,
      ): Promise<{ access_token: string }> {
        const user = await this.usersService.findOne(username);
        if (user?.password !== password) {
          throw new UnauthorizedException();
        }
        const payload = { sub: user.userId, username: user.username };
    
        return { access_token: await this.jwtService.sign(payload) };
      }
    }
    
  • meta파일 생성

    • /src/util/public.meta.ts
    import { SetMetadata } from '@nestjs/common';
    
    export const IS_PUBLIC_KEY = 'isPublic';
    export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
    
  • guard파일 생성

  • /src/auth/auth.guard.ts

import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Observable } from 'rxjs';
import { jwtConstants } from './constants';
import { Request } from 'express';
import { Reflector } from '@nestjs/core';
import { IS_PUBLIC_KEY } from 'src/util/public.meta';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private readonly jwtService: JwtService,
    private readonly reflector: Reflector,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) {
      return true;
    }
    const request = context.switchToHttp().getRequest<Request>();
    const token = this.extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      const payload = await this.jwtService.verifyAsync(token, {
        // secret: process.env.JWT_SECRET,
        secret: jwtConstants.secret,
      });
    } catch (e) {
      throw new UnauthorizedException();
    }
    return true;
  }
  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}
  • main.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { AuthGuard } from './auth/auth.guard';

@Module({
  imports: [AuthModule, UsersModule],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: 'APP_GUARD',
      useClass: AuthGuard,
    },
  ],
})
export class AppModule {}

0개의 댓글