๐Ÿ’ป ํ”„๋กœ์ ํŠธ/๐ŸŽ“ RESUMAI

[RESUMAI] 6. ์„œ๋น„์Šค ๊ฐœ๋ฐœ ์‹œ์ž‘ - DRF ์นด์นด์˜ค ์†Œ์…œ๋กœ๊ทธ์ธ, ์ด๊ฒƒ๋งŒ ๋ณด๋ฉด ํ•œ๋ฒˆ์— ๋!!

์žฅ์˜์ค€ 2024. 5. 25. 17:37

์ง€๋‚œ๋ฒˆ๊นŒ์ง€ ๋ฐ๋ชจ๋ฅผ ๋งˆ์น˜๊ณ , ์ด์ œ ์ œ๋Œ€๋กœ RESUMAI ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” ์ด์ „์— ๋ฐ๋ชจ์—์„œ ๋ณด์—ฌ์ค€ ์•„์ด๋””์–ด๋กœ, ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์„ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๋ณธ ํ”„๋กœ์ ํŠธ๋Š” Django Rest Framework (DRF)๋กœ ๊ฐœ๋ฐœํ•˜์˜€์œผ๋ฉฐ, ํ”„๋ก ํŠธ์—”๋“œ๋Š” React๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. (๋‚˜๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ๋งŒ ๋งก์•˜๋‹ค.)

๋ณธ ๊ธ€์€ DRF๋กœ ์นด์นด์˜ค ์†Œ์…œ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•˜๋ฉฐ ๊ฒช์—ˆ๋˜ ์–ด๋ ค์›€์„ ๋ชจ๋‘ ๋‹ด์•˜๋‹ค.

 

์•„๋งˆ DRF๋กœ ์ฒ˜์Œ ์†Œ์…œ๋กœ๊ทธ์ธ์„ ๊ฐœ๋ฐœํ•ด๋ณด๋ ค๋Š” ์‚ฌ๋žŒ๋“ค๋„ ๋ณธ ๊ธ€๋งŒ ๋ณด๋ฉด ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋ชจ๋‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค !!

 


1. Models

์นด์นด์˜ค ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•˜๊ธฐ์— ์•ž์„œ ๋จผ์ € user model์„ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ์‚ฌ์‹ค ์ด model์€ ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, ๊ธฐ๋ณธ์ ์ธ ๊ฒƒ๋“ค์„ ์ œ์™ธํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ๋”ฐ๋กœ customize ํ•ด์•ผ ํ•œ๋‹ค.

๋ฒ ์ด์Šค๊ฐ€ ๋˜๋Š” ์œ ์ € ๋ชจ๋ธ์€ ๋‹ค์Œ ๊ธ€์„ ์ฐธ๊ณ ํ•ด๋ณด๋ฉด ์ข‹๋‹ค.

1โ€“1. ์นด์นด์˜ค ๋น„์ฆˆ์•ฑ ๋“ฑ๋ก

์ฒ˜์Œ์— ๋‚˜๋Š” ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์‹œ, ๋น„์ฆˆ๋‹ˆ์Šค ๊ณ„์ •์œผ๋กœ ๋“ฑ๋ก์ด ์•ˆ๋˜์–ด ์žˆ์œผ๋ฉด ์ด๋ฉ”์ผ์„ ๋ฐ˜ํ™˜๋ฐ›์ง€ ๋ชปํ•œ๋‹ค๋Š” ์ •๋ณด๋ฅผ ๋“ฃ๊ณ , ์ •๋ง ๋งŽ์€ ๊ณ ๋ฏผ์„ ํ–ˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ฒ˜์Œ์—๋Š” oid(์นด์นด์˜ค์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ์œ ์ € id)๋ฅผ ๊ณ ์œ  ํ•„๋“œ๋กœ ์‚ผ์•„์•ผ ํ•˜๋‚˜? ๋ผ๋Š” ๊ณ ๋ฏผ์„ ํ•˜๊ณ , ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๊ตฌํ˜„๋„ ํ–ˆ์—ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ์„œ์นญ ๋์— ๊ฐœ์ธ๊ฐœ๋ฐœ์ž ๋น„์ฆˆ ์•ฑ ์ „ํ™˜์„ ํ†ตํ•ด ์ด๋ฉ”์ผ์„ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ •๋ณด๋ฅผ ์•Œ๊ฒŒ ๋˜์–ด, ๋ฐ”๋กœ ๋น„์ฆˆ์•ฑ ์ „ํ™˜์„ ์‹ ์ฒญํ–ˆ๋‹ค. (๋น„์ฆˆ์•ฑ ์ „ํ™˜์€ ๊ทธ๋ƒฅ ์นด์นด์˜ค ๋””๋ฒจ๋กœํผ์Šค ํ™ˆํŽ˜์ด์ง€์—์„œ ์‹ ์ฒญํ•˜๋ฉด ๋œ๋‹ค.)

1โ€“2. model ์ •์˜

๋จผ์ €, ๋‚ด ํ”„๋กœ์ ํŠธ์˜ user ERD๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์•˜๋‹ค.

์œ ์ € ์ •๋ณด๋ฅผ ํฌ๊ฒŒ ์ €์žฅํ•  ๊ฒƒ์ด ์—†์–ด์„œ..์ƒ๊ฐ๋ณด๋‹ค ๋ณ„๋กœ ๋„ฃ์„ ๊ฒŒ ์—†์—ˆ๋‹ค..ใ…Žใ…Ž

๊ทธ๋ž˜์„œ ๋จผ์ € python manage.py startapp accounts ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด accounts ์•ฑ์„ ๋งŒ๋“ค๊ณ , ๊ทธ ์•ˆ์˜ models.py์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ–ˆ๋‹ค.

class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    username = models.CharField(max_length=100, unique=False)  # username ํ•„๋“œ
    kakao_oid = models.BigIntegerField(
        null=True, unique=True, blank=False
    )  # ์นด์นด์˜ค user_id

    position = models.CharField(max_length=100, null=True, blank=True)
    profile_image = models.URLField(max_length=200, blank=True)

    is_staff = models.BooleanField(default=False)  # ์Šˆํผ์œ ์ € ๊ถŒํ•œ
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)  # ๊ณ„์ • ํ™œ์„ฑํ™” ์ƒํƒœ
    created_at = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def save(self, *args, **kwargs):

        super().save(*args, **kwargs)

    def __str__(self):
        return self.email

์ค‘๊ฐ„์— CutomUserManager ๋ผ๋Š” manager๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด๋Š” managers.py์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค.

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("์ด๋ฉ”์ผ ํ•„๋“œ๊ฐ€ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        return self.create_user(email, password, **extra_fields)

์ด manager์˜ ์—ญํ• ์€ ์œ ์ € ๋ฐ ์Šˆํผ์œ ์ €๋ฅผ ๋งŒ๋“ค ๋•Œ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๊ณ , ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ํ•„๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ํ•„๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฒฝ๊ณ ํ•˜๋Š” ์—ญํ• ์ด๋‹ค.

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ–ˆ์œผ๋ฉด, python manage.py makemigrations && migrate ๋ฅผ ํ†ตํ•ด ์œ ์ € ๋ชจ๋ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

2. ์ธ์ฆ ๋กœ์ง

์ด๋ ‡๊ฒŒ user model์„ ์ •์˜ํ•œ ํ›„์—๋Š”, ์ธ์ฆ ๋กœ์ง์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋จผ์ €, ์•„์ฃผ ์ž˜ ์•Œ๋ ค์ง„ ์นด์นด์˜ค ์ธ์ฆ ๋กœ๊ทธ์ธ ๋กœ์ง ๊ทธ๋ฆผ์„ ํ•œ๋ฒˆ ๋ณด๋ฉด,

๊ฐ„๋žตํ•˜๊ฒŒ ๋งํ•ด ๋กœ์ง์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์š”์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ํด๋ผ์ด์–ธํŠธ์—์„œ ์นด์นด์˜ค ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„ ์„œ๋ฒ„์— ์ „๋‹ฌํ•œ๋‹ค.
  2. ์„œ๋ฒ„๋Š” ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ์นด์นด์˜ค์—์„œ์˜ ์‚ฌ์šฉ์ž์˜ access, refresh token์„ ์ „๋‹ฌ ๋ฐ›๋Š”๋‹ค. ์ด๋•Œ, access token๊ณผ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  3. ํด๋ผ์ด์–ธํŠธ๊ฐ€ acess token๊ณผ code๋ฅผ ์„œ๋ฒ„์—๊ฒŒ ๋ณด๋‚ด๋ฉด, ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜๊ณ , ๋‚ด๋ถ€์—์„œ access, refresh token, code๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ด์ œ ์ด ๋กœ์ง์„ ๊ทธ๋Œ€๋กœ ๊ตฌํ˜„ํ•ด๋ณด์ž. ๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๊ตฌํ˜„์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด allauth์™€ dj_rest_auth๋ฅผ์‚ฌ์šฉํ–ˆ๋‹ค.

3. Views

์•ž์„œ ์ฒจ๋ถ€ํ•œ ์ธ์ฆ ๋กœ์ง์„ ๋ณด๋ฉด,

  • ์นด์นด์˜ค ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ธ‰ํ•˜๋Š” view
  • ์นด์นด์˜ค์—์„œ ๋ฐ˜ํ™˜ํ•œ access_token๊ณผ code๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์นด์นด์˜ค ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” view

์œ„์™€ ๊ฐ™์€ 2๊ฐœ์˜ view๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ์‹ค ์นด์นด์˜ค ์ธ๊ฐ€ ์ฝ”๋“œ ๋ฐœ๊ธ‰ํ•˜๋Š” view๋Š” ์นด์นด์˜ค ๋””๋ฒจ๋กœํผ์Šค ํ™ˆํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐ€ redirect uri๋งŒ ์ž˜ ์„ค์ •ํ•ด ์ฃผ๊ณ , ์•„๋ž˜ url๋กœ ์ ‘์†ํ•˜๋ฉด ๋œ๋‹ค.

"https://kauth.kakao.com/oauth/authorize?client_id={REST_API_KEY}&redirect_uri={KAKAO_CALLBACK_URI}&response_type=code"

 

๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‚˜๋จธ์ง€ 1๊ฐœ์˜ view์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

๋จผ์ € ์ „์ฒด ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

# accouts/views.py
User = get_user_model()

class KakaoLoginView(APIView):
    def post(self, request, *args, **kwargs):
        code = request.data.get("code")

        if not code:
            return Response(
                {"error": "Code is required"}, status=status.HTTP_400_BAD_REQUEST
            )

        # ์นด์นด์˜ค ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด access_token ํš๋“
        token_res = requests.get(
            f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={REST_API_KEY}&client_secret={CLIENT_SECRET}&redirect_uri={KAKAO_CALLBACK_URI}&code={code}"
        )
        logger.fatal(token_res)

        if token_res.status_code != 200:
            logger.fatal(token_res.json())
            return Response(
                {"error": "Failed to obtain access token"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        token_json = token_res.json()
        access_token = token_json.get("access_token")

        # ์นด์นด์˜ค access_token์œผ๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž ์ •๋ณด ํš๋“
        headers = {"Authorization": f"Bearer {access_token}"}
        profile_res = requests.get("https://kapi.kakao.com/v2/user/me", headers=headers)

        if profile_res.status_code != 200:
            return Response(
                {"error": "Failed to obtain user information"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        profile_json = profile_res.json()

        kakao_oid = profile_json.get("id")
        nickname = profile_json.get("properties")["nickname"]
        profile_image = profile_json.get("properties")["profile_image"]
        email = profile_json.get("kakao_account")["email"]

        user, created = User.objects.get_or_create(
            email=email,
            defaults={
                "username": f"{nickname}",
                "kakao_oid": kakao_oid,
                "profile_image": f"{profile_image}",
            },
        )

        # ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ํ† ํฐ ์ƒ์„ฑ
        refresh = RefreshToken.for_user(user)
        data = {
            "access_token": str(refresh.access_token),
            "refresh_token": str(refresh),
            "user_info": {
                "id": user.id,
                "email": user.email,
                "username": user.username,
                "profile_image": user.profile_image,
                "is_created": created,
            },
        }

        return Response(data, status=status.HTTP_200_OK)

์ด ์ฝ”๋“œ ์กฐ๊ฐ์„ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด์ž.

3-1. ์ธ๊ฐ€ ์ฝ”๋“œ ๋ฐ›์•„์˜ค๊ธฐ

User = get_user_model()

def kakao_login(request):
    return redirect(
        f"https://kauth.kakao.com/oauth/authorize?client_id={REST_API_KEY}&redirect_uri={KAKAO_CALLBACK_URI}&response_type=code"
    )

์ด ๋ถ€๋ถ„์€ ํด๋ผ์ด์–ธํŠธ ๋ถ€๋ถ„๊ณผ์˜ ์‹ฑํฌ๋ฅผ ๋งž์ถ”๊ธฐ ์œ„ํ•ด์„œ ์ž‘์„ฑํ–ˆ๋Š”๋ฐ, ์œ„์— ์ž‘์„ฑํ•œ url๋กœ ์ ‘์†ํ•˜๋ฉด code? ๋ผ๋Š” query๋กœ ์นด์นด์˜ค์—์„œ ์ธ์ž ์ฝ”๋“œ๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.

์˜ˆ์‹œ

์ด๋ ‡๊ฒŒ ๋’ค์˜ code๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํŒŒ์‹ฑํ•˜์—ฌ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋ฉด, ์นด์นด์˜ค์˜ AT (Access Token)์„ ๋ฐ›์•„ ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๊ณ , ์ž์ฒด AT, RT๋ฅผ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

3-2. ์ž์ฒด AT, RT ๋ฐ˜ํ™˜

1. ์ธ๊ฐ€์ฝ”๋“œ๋กœ ์นด์นด์˜ค access_token ํš๋“

๋จผ์ €, ์‚ฌ์šฉ์ž๊ฐ€ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ postํ•˜๊ฒŒ ํ•˜์—ฌ, kauth๋กœ๋ถ€ํ„ฐ ์นด์นด์˜ค AT๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๋Š”๋‹ค.
์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

class KakaoLoginView(APIView):
    def post(self, request, *args, **kwargs):
        code = request.data.get("code")

        if not code:
            return Response(
                {"error": "Code is required"}, status=status.HTTP_400_BAD_REQUEST
            )

        # ์นด์นด์˜ค ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด access_token ํš๋“
        token_res = requests.get(
            f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={REST_API_KEY}&client_secret={CLIENT_SECRET}&redirect_uri={KAKAO_CALLBACK_URI}&code={code}"
        )

        if token_res.status_code != 200:
            return Response(
                {"error": "Failed to obtain access token"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        token_json = token_res.json()
        access_token = token_json.get("access_token")

2. ์ธ๊ฐ€์ฝ”๋“œ๋กœ ์นด์นด์˜ค access_token ํš๋“

๊ทธ๋ ‡๊ฒŒ ๋ฐ›์€ ์นด์นด์˜ค AT๋ฅผ Bearer์™€ ํ•จ๊ป˜ header๋กœ ์œ ์ € ํ”„๋กœํ•„์„ ๋ฐ›์•„์˜ค๋Š” request๋ฅผ ๋ณด๋‚ธ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด, ์œ ์ €์˜ ์นด์นด์˜ค oid,๋‹‰๋„ค์ž„, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€, email์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ดํ›„, โ€˜user, created = User.objects.get_or_createโ€™ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ โ€˜userโ€™๋กœ ์œ ์ € ์ •๋ณด๋ฅผ, โ€˜createdโ€™๋กœ ์œ ์ €๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

        # ์นด์นด์˜ค access_token์œผ๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž ์ •๋ณด ํš๋“
        headers = {"Authorization": f"Bearer {access_token}"}
        profile_res = requests.get("https://kapi.kakao.com/v2/user/me", headers=headers)

        if profile_res.status_code != 200:
            return Response(
                {"error": "Failed to obtain user information"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        profile_json = profile_res.json()

        kakao_oid = profile_json.get("id")
        nickname = profile_json.get("properties")["nickname"]
        profile_image = profile_json.get("properties")["profile_image"]
        email = profile_json.get("kakao_account")["email"]

        user, created = User.objects.get_or_create(
            email=email,
            defaults={
                "username": f"{nickname}",
                "kakao_oid": kakao_oid,
                "profile_image": f"{profile_image}",
            },
        )

3. ์ž์ฒด AT, RT ์ƒ์„ฑ

๋งˆ์ง€๋ง‰์œผ๋กœ, rest_framework ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ RefreshToken์„ ์‚ฌ์šฉํ•ด์„œ ์ž์ฒด RT, AT๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ๋ณธ์ธ์€ user_info๋„ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค.

from rest_framework_simplejwt.tokens import RefreshToken

        # ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ํ† ํฐ ์ƒ์„ฑ
        refresh = RefreshToken.for_user(user)
        data = {
            "access_token": str(refresh.access_token),
            "refresh_token": str(refresh),
            "user_info": {
                "id": user.id,
                "email": user.email,
                "username": user.username,
                "profile_image": user.profile_image,
                "is_created": created,
            },
        }

        return Response(data, status=status.HTTP_200_OK)

4. ๊ฒฐ๊ณผ

Swagger๋กœ ๋ณด์ด๋Š” ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์‹ค์ œ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ•˜์—ฌ ์‹คํ–‰ํ•ด๋ณด๋ฉด ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๊ฒฐ๊ตญ์€ ๊ทธ๋ƒฅ 1๊ฐœ์˜ api๋งŒ ์žˆ์œผ๋ฉด ๋๋‚œ๋‹ค. (url๋กœ ์ ‘์†ํ•ด์„œ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ž‘์—…์€ ์•ž์„œ ๋งํ–ˆ๋“ฏ์ด ๊ทธ๋ƒฅ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์—..)


 

์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ DRF๋กœ ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ๋๋ƒˆ๋‹ค. ์ƒ๊ฐ๋ณด๋‹ค ํฌ๊ฒŒ ํ• ๊ฒŒ ๋ณ„๊ฑฐ ์—†์—ˆ๋Š”๋ฐ ๊ฐœ๊ณ ์ƒํ–ˆ๋˜ ๊ธฐ์–ต์ด ์žˆ๋‹ค. ใ…‹ใ…‹ใ…‹ใ…‹

๋‹ค์Œ ๊ธ€์—์„œ๋Š” DRF+Docker+ELB ๋ฐฐํฌ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณผ ์˜ˆ์ •์ด๋‹ค.

๋Œ“๊ธ€์ˆ˜0