OAuth 연동 로그인 리펙토링

JBoB·2023년 2월 14일
0
post-custom-banner

🐧OAuth 연동 로그인 리펙토링

저번에 만들었던 OAuth 로그인 코드를 좀더 알아보기 쉽고 간결하게 만들어 보자.

OAuth (소셜 로그인 연동)

전에 만들었던 카카오 네이버 구글 로그인을 참고하기 바란다.

리팩토링은 총 4단계 각 단계별로 리팩토링 절차

엔드포인트가 다 똑같다.

로그인을 다통일 시켜준다.

그리고 엔드포인트를 :social 이라는 매개변수로 바꿔준다.

req.params 이안에 :social 이 네이버인지 카카오인지 들어오게 준다.

req.params 을 오스가드안에 어떻게 넣어줄 것이냐

오스가드 노드모듈에 conactive함수가 실행된다. 이것을 req.params 가 들어갈 수 있게 수정해줘야한다.

그러기 위해선 동적으로 변경된 오스가드를 만들어준다

implements 를 활용해 canactive으로 구현해야 하는 다이나믹 클래스를 만들어주세요

context.switchtoHttp 를 활용해 rep,res를 담고 있는 것으로 만들어준다.

auth.controller.ts

2단계

새로운 파일 dynamic-auth-guard.ts 생성

import { CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

class GoogleAuthGuard extends AuthGuard('google') {}
class KaKaoAuthGuard extends AuthGuard('google') {}
class NaverAuthGuard extends AuthGuard('google') {}

const googleAuthGuard = new GoogleAuthGuard();
const kakaoAuthGuard = new GoogleAuthGuard();
const naverAuthGuard = new GoogleAuthGuard();

export class DynamicAuthGuard implements CanActivate {
  canActivate(context: ExecutionContext) {
    const { social } = context.switchToHttp().getRequest().params;
// params는 GET 또는 POST 요청을 통해 컨트롤러에 전달되는 매개 변수를 나타냅니다.
// GET 요청에서 매개 변수는 사용자 브라우저의 URL에서 컨트롤러로 전달된다.

    if (social === 'google') return googleAuthGuard.canActivate(context);
    if (social === 'kakao') return kakaoAuthGuard.canActivate(context);
    if (social === 'naver') return naverAuthGuard.canActivate(context);
//여기도 반복되는 로직이 많다 다시 리펙토링 해주자 
  }
}

새로운 파일 dynamic-auth-guard.ts-02 생성

import { CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

class GoogleAuthGuard extends AuthGuard('google') {}
class KaKaoAuthGuard extends AuthGuard('google') {}
class NaverAuthGuard extends AuthGuard('google') {}
// 변하지 않는 상수값은 대문자로 사용
const DYNAMIC_AUTH_GUARD = {
  google: new GoogleAuthGuard(),
  kakao: new KaKaoAuthGuard(),
  naver: new NaverAuthGuard(),
};

export class DynamicAuthGuard implements CanActivate {
  canActivate(context: ExecutionContext) {
    const { social } = context.switchToHttp().getRequest().params;
    return DYNAMIC_AUTH_GUARD[social].canActivate(context);
  }
}

객체가 연결되는 곳을 찬찬히 보자면~

object literal look up

: if if if 들을 하나의 객체로 리펙토링 해줘 리턴 해줄수 있다 그러면 효율적 쓸수 있다.

3단계 dynamic-auth-guard.ts-03 생성

import { CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

//class를 객체 안에 합칠수 있음
const DYNAMIC_AUTH_GUARD = {
  // class 부모 클래스는 익명 클래스로 생략가능
  // 이 자체가 function이기 때문에 뒤에 () 붙여야 한다. 그래야 인자를 불러올수 있다.
  google: new (class extends AuthGuard('google') {})(),
  kakao: new (class extends AuthGuard('google') {})(),
  naver: new (class extends AuthGuard('google') {})(),
};

export class DynamicAuthGuard implements CanActivate {
  canActivate(context: ExecutionContext) {
    const { social } = context.switchToHttp().getRequest().params;
    return DYNAMIC_AUTH_GUARD[social].canActivate(context);
  }
}

마지막 4단계 dynamic-auth-guard.ts-04 생성

import { CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

// 한번씩 구글 카카오 네이버가 curr값으로 순차적으로 들어온다.
// prev 기준값이 계속 누적되어 들어온다.
const DYNAMIC_AUTH_GUARD = ['google', 'kakao', 'naver'].reduce((prev, curr) => {
  return {
    // prev에 담겨있는 값을 합쳐주기 위해 스프레드 연산자를 쓴다.
    ...prev,
    // curr은 result.key로 되어버리기 때문에 curr은 변수인데 그 변수를 키로 만들고 싶다
    // 그렇다고 []로 감싸준다고 해서 []배열은 아니다.
    // 객체의 키값에는 []로 감싸줘야한다 !!! 중요
    [curr]: new (class extends AuthGuard(curr) {})(),
  };
}, {});

					// 단계별로 
// prev?
// const result =
// 
//   [curr]: new (class extends AuthGuard(curr){})()
// }

// map,forEach,reduce 를 써줘서 하나씩 넣어줄수 있다.
// 1단계 빈 객체 생성
// {}

// 2단계 구글만 집어넣는다.
// {
//  google: new (class extends AuthGuard('google') {})(),
// }

// 3단계 카카오 추가
// {
//  google: new (class extends AuthGuard('google') {})(),
//  kakao: new (class extends AuthGuard('google') {})(),
// }

// 4단계 네이버 추가
// {
//  google: new (class extends AuthGuard('google') {})(),
//  kakao: new (class extends AuthGuard('google') {})(),
//  naver: new (class extends AuthGuard('google') {})(),
// }

export class DynamicAuthGuard implements CanActivate {
  canActivate(context: ExecutionContext) {
    const { social } = context.switchToHttp().getRequest().params;
    return DYNAMIC_AUTH_GUARD[social].canActivate(context);
  }
}

const DYNAMIC_AUTH_GUARD = ['google', 'kakao', 'naver'].reduce((prev, curr) => {
  const result = {
    // prev에 담겨있는 값을 합쳐주기 위해 스프레드 연산자를 쓴다.
    ...prev,
    // curr은 result.key로 되어버리기 때문에 curr은 변수인데 그 변수를 키로 만들고 싶다
    // 그렇다고 []로 감싸준다고 해서 []배열은 아니다.
    // 객체의 키값에는 []로 감싸줘야한다 !!! 중요
    [curr]: new (class extends AuthGuard(curr) {})(),
  };
  // return 을 해줘야 curr의 값이 반환되어 prev의 값으로 전달된다.
  return result;
},{});

result를 그냥 return 으로 합쳐서 쓸수 있다.

============> 4단계 파일 

const DYNAMIC_AUTH_GUARD = ['google', 'kakao', 'naver'].reduce((prev, curr) => {
  return {
    // prev에 담겨있는 값을 합쳐주기 위해 스프레드 연산자를 쓴다.
    ...prev,
    // curr은 result.key로 되어버리기 때문에 curr은 변수인데 그 변수를 키로 만들고 싶다
    // 그렇다고 []로 감싸준다고 해서 []배열은 아니다.
    // 객체의 키값에는 []로 감싸줘야한다 !!! 중요
    [curr]: new (class extends AuthGuard(curr) {})(),
  };
}, {});

실무에서는 보통 2번코드가 더 좋다 .

소스코드가 단순하면 4번코드로 축약해서 쓰는것도 좋다.

유지보수가 머가 더 쉬운지 고민해서 선택해서 쓰는것이 좋다.(팀원들이 알아볼수 있는 코드로)

profile
간절하고 치열하게 살자
post-custom-banner

0개의 댓글