[2024.08.14 TIL] 내일배움캠프 85일차 (최종 팀프로젝트, 레디스를 이용한 소셜 로그인 고도화)

My_Code·2024년 8월 14일
0

TIL

목록 보기
100/113
post-thumbnail

본 내용은 내일배움캠프에서 활동한 내용을 기록한 글입니다.


💻 TIL(Today I Learned)

📌 Today I Done

✏️ 레디스를 이용한 소셜 로그인 고도화

  • 기존에는 아래처럼 카카오 로그인 백엔드 API를 호출하면 생성한 토큰을 URL에 넣어서 리다이렉트 진행함

http://localhost:3000/views/auth/kakao/process?accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNzIzNjQyOTY1LCJleHAiOjE3MjM2ODYxNjV9.s7zGGcTvhoPTX7-POWEdebCBFcAqshbcL7588HJg9N4&refreshToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNzIzNjQyOTY1LCJleHAiOjE3MjQyNDc3NjV9.1ZF2P49nnHQs0FJV7bDKPedTcDt0euQldSByWe8guus
  /**
   * 카카오 로그인
   * @param req
   * @returns
   */
  @UseGuards(KakaoAuthGuard)
  @Get('/kakao')
  async kakaoSignIn(@Req() req: any, @Res() res: any) {
    const { accessToken, refreshToken } = await this.authService.signIn(
      req.user,
      Provider.KAKAO,
      true
    );
    res.redirect(
      `${process.env.HOST_NAME}/views/auth/kakao/process?accessToken=${accessToken}&refreshToken=${refreshToken}`
    );
  }
  • 하지만 이러한 방식은 토큰이 그대로 들어나기 때문에 보안적으로 매우 취약함

  • 그래서 고안한 방법이 랜덤 코드를 만들어서 해당 코드를 키로 하는 사용자 ID를 레디스에 저장하는 방식임

  • 이 방식의 순서는 다음과 같음

    1. 카카오 소셜 로그인을 진행함
    2. 리다이렉트를 통해서 백엔드 API가 호출됨
    3. 그 백엔드 API의 KakaoStrategy를 통해서 로그인한 사용자가 유효한지 검증함
    4. 유효하면 고유한 값(uuid) code를 키, 해당 사용자의 ID를 값으로 설정해서 레디스에 저장
    5. 프론트엔드에게 Query로 code를 넘김
    6. 프론트엔드는 다시 해당 code를 Query를 이용해서 토큰을 발급하는 백엔드 API를 호출
    7. 토큰을 발급하는 백엔드 API는 토큰을 발급해서 Body에 담아서 반환
    8. 프론트엔드는 받은 토큰을 저장
  • 아래는 code를 넘기는 방식으로 했을 때의 URL과 컨트롤러 코드임

  /**
   * 카카오 로그인 코드 생성
   * @param req
   * @returns
   */
  @UseGuards(KakaoAuthGuard)
  @Get('/kakao')
  async kakaoSignIn(@Req() req: any, @Res() res: any) {
    // 탈퇴한 소셜 로그인 유저라면
    if (req.user.deletedAt !== null) {
      res.redirect(`${process.env.HOST_NAME}/views/auth/sign?error=이미 탈퇴한 사용자입니다.`);
    } else {
      const code = await this.authService.createCode(req.user.id);
      res.redirect(`${process.env.HOST_NAME}/views/auth/kakao/process?code=${code}`);
    }
  }

  /**
   * 카카오 로그인 토큰 발급
   * @param req
   * @returns
   */
  @Get('/kakao/token')
  async getKakaoToken(@Query('code') code: string) {
    // code를 통해 레디스에서 사용자 ID 가져오기
    const userId = await this.authService.getRedisUserId(code);
    const { accessToken, refreshToken } = await this.authService.signIn(+userId);
    return { accessToken, refreshToken };
  }
  • 그리고 아래는 레디스에 데이터를 저장하는 방법과 불러오는 방법에 대한 코드임
  // 소셜 로그인 코드 발급
  async createCode(userId: number) {
    const code = uuidv4();

    // 레디스에 코드 - 사용자 ID 형태로 저장
    await this.redisClient.set(code, userId, 'EX', 20);
    return code;
  }

  // 레디스에서 사용자 ID 가져오기
  async getRedisUserId(code: string) {
    return await this.redisClient.get(code);
  }


📌 Tomorrow's Goal

✏️ 스트레스 테스트 진행하기

  • 내일은 서비스에 대한 스트레스 테스트를 진행할 예정

  • 특히 인덱스 설정을 했을 때와 하지 않았을 때의 읽는 속도를 비교할 예정

  • 처음에는 1000명으로 시작해서 최대 100만명까지로 테스트할 예정



📌 Today's Goal I Done

✔️ 레디스를 이용한 소셜 로그인 고도화

  • 원래 오늘 스트레스 테스트를 진행할 예정이었지만, 레디스를 이용한 소셜 로그인 고도화를 먼저 진행하자고 말씀하셨음

  • 그 이유는 스트레스 테스트에서 정말 유의미한 결과가 나올지 모르기 때문에 확실하게 적용하는 이유가 있는 레디스를 이용한 소셜 로그인 고도화를 먼저 진행하자고 하셨음

  • 그래서 오늘 클라우드 레디스 데이터베이스를 만들고 해당 데이터베이스에서 작업을 진행함

  • 기존에 팀원들이 기본적인 설정을 다 했기 때문에 비교적 간단하게 적용이 가능했음



⚠️ 구현 시 발생한 문제

✔️ cannot drop index needed in a foreign key constraint

  • 오늘 서버 실행 중 터미널에 cannot drop index needed in a foreign key constraint와 같은 에러가 발생함

  • 발생하는 이유는 코드 상에서 외래키에 @Index()를 줬다가 제거하는 과정에서 데이터베이스의 인덱스와 충돌이 발생했기 때문에 생긴 에러임

  • 관계를 설정하고 외래키를 만들면 아래와 같이 자동적으로 데이터베이스에서 인덱스를 만들어 줌

  • 그런데 그 사실을 모르고 또다시 인덱스를 설정해서 별도의 IDX_~라는 이름의 인덱스가 생겼고 그래서 외래키 쪽과 충돌이 발생했음

  • 해결 방법은 코드에서 중복으로 작성한 인덱스들을 지우고 데이터베이스에 가서 IDX_~와 관련된 외래키와 인덱스를 지워야 함

    1. IDX_~와 관련된 테이블에 들어가서 외래키를 먼저 다 지우고 저장
    2. 인덱스에서 IDX_~로 시작하는 인덱스를 지우면 해결
  • 다만, 여기서 지우면 안되는 것들이 존재함

    • IDX_~로 시작하지만 unique 설정이 있는 경우
    • unique 옵션을 사용하면 자동으로 IDX_~로 시작하는 인덱스가 생성됨
    • 당연하겠지만 기본키(PK) 관련 인덱스도 지우면 안됨
profile
조금씩 정리하자!!!

0개의 댓글