Skip to content

로그인 & 회원가입

hyukjunkim1116 edited this page Jul 6, 2023 · 3 revisions

✔️ 로그인

  • 로그인 시 fetch를 사용하여 DB에 있는 이메일과 PW를 가져와 사용자가 입력한 값과 비교해서 값이 일치할 때 로그인 허용
  • 로그인 시 2시간 동안 jwt 토큰을 로컬스토리지에 저장
  • 소셜 로그인시 이메일이 기존에 있는지 파악후 중복되면 로그인 제한

💻 code

users/serializers.py
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token["id"] = user.id
        token["email"] = user.email
        token["username"] = user.username
        token["login_type"] = user.login_type
        token["avatar"] = user.avatar
        return token
users/views.py
def social_login_validate(**kwargs):
    data = {k: v for k, v in kwargs.items()}
    email = data.get("email")
    login_type = data.get("login_type")
    if not email:
        return Response(
            {"error": "해당 계정에 email정보가 없습니다."}, status=status.HTTP_400_BAD_REQUEST
        )
    try:
        user = User.objects.get(email=email)
        if login_type == user.login_type:
            refresh = RefreshToken.for_user(user)
            access_token = serializers.CustomTokenObtainPairSerializer.get_token(user)
            return Response(
                {"refresh": str(refresh), "access": str(access_token.access_token)},
                status=status.HTTP_200_OK,
            )
        else:
            return Response(
                {"error": f"{user.login_type}으로 이미 가입된 계정이 있습니다!"},
                status=status.HTTP_400_BAD_REQUEST,
            )
    except User.DoesNotExist:
        # with transaction.atomic():
        new_user = User.objects.create(**data)
        new_user.set_unusable_password()
        new_user.save()
        refresh = RefreshToken.for_user(new_user)
        access_token = serializers.CustomTokenObtainPairSerializer.get_token(new_user)
        html = render_to_string(
            "users/email_welcome.html",
            {
                "front_base_url": settings.FRONT_BASE_URL,
                "user": new_user,
            },
        )
        to_email = new_user.email
        send_mail(
            "안녕하세요 Cookai입니다. 회원가입을 축하드립니다!",
            "_",
            settings.DEFAULT_FROM_MAIL,
            [to_email],
            html_message=html,
        )
        return Response(
            {"refresh": str(refresh), "access": str(access_token.access_token)},
            status=status.HTTP_200_OK,
        )

📷 View

Image

✔️ 회원가입

  • 회원가입 시 이메일 인증을 통해 유효한 이메일인지 확인한다.
  • 비밀번호 전용 validator를 생성하여 모델에 적용.
  • 이메일 유무, 유저 존재 유무 비밀번호와 확인 비밀번호가 일치하는지 판단 후 유저 생성
  • 이메일 인증이 완료되면 유저의 is_active=True로 변경.

💻 code

users/views.py
class UserView(APIView):

    def post(self, request):
        email = request.data.get("email")
        password = request.data.get("password")
        password2 = request.data.get("second_password")
        username = request.data.get("username")
        if not password or not password2:
            return Response(
                {"error": "비밀번호 입력은 필수입니다!"}, status=status.HTTP_400_BAD_REQUEST
            )
        if not email:
            return Response(
                {"error": "이메일 입력은 필수입니다!"}, status=status.HTTP_400_BAD_REQUEST
            )
        if password != password2:
            return Response(
                {"error": "비밀번호가 일치하지 않습니다!"}, status=status.HTTP_400_BAD_REQUEST
            )
        if User.objects.filter(email=email).exists():
            return Response(
                {"error": "해당 이메일을 가진 유저가 이미 있습니다!"}, status=status.HTTP_400_BAD_REQUEST
            )
        if User.objects.filter(username=username).exists():
            return Response(
                {"error": "해당 닉네임을 가진 유저가 이미 있습니다!"}, status=status.HTTP_400_BAD_REQUEST
            )
        serializer = UserSerializer(
            data=request.data,
            context={"request": request},
        )
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(
                serializer.errors,
                status=status.HTTP_400_BAD_REQUEST,
            )
users/validators.py
def validate_password(password):
    if len(password) < 8:
        raise ValidationError({"password": "비밀번호는 8자리 이상이어야 합니다."})
    if not re.search(r"[a-zA-Z]", password):
        raise ValidationError({"password": "비밀번호는 하나 이상의 영문이 포함되어야 합니다."})
    if not re.search(r"\d", password):
        raise ValidationError({"password": "비밀번호는 하나 이상의 숫자가 포함되어야 합니다."})
    if not re.search(r"[!@#$%^&*()]", password):
        raise ValidationError(
            {"password": "비밀번호는 적어도 하나 이상의 특수문자(!@#$%^&*())가 포함되어야 합니다."}
        )
    return password
users/validators.py
class UserSignUpPermitView(APIView):
    def get(self, request, uidb64, token):
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
            if account_activation_token.check_token(user, token):
                User.objects.filter(pk=uid).update(is_active=True)

                html = render_to_string(
                    "users/email_welcome.html",
                    {
                        "front_base_url": settings.FRONT_BASE_URL,
                        "user": user,
                    },
                )
                to_email = user.email
                send_mail(
                    "안녕하세요 Cookai입니다. 회원가입을 축하드립니다!",
                    "_",
                    settings.DEFAULT_FROM_MAIL,
                    [to_email],
                    html_message=html,
                )
                return redirect(f"{settings.FRONT_BASE_URL}/login.html")
            return Response({"error": "AUTH_FAIL"}, status=status.HTTP_400_BAD_REQUEST)
        except:
            return Response({"error": "KEY_ERROR"}, status=status.HTTP_400_BAD_REQUEST)

📷 View

Image
Clone this wiki locally