Django 이메일로 로그인하기

Gom La·2023년 5월 13일
1

장고와 친해지기

목록 보기
16/17
post-thumbnail

✔️ 이전 로그인 기능에는 아래와 같이 username, email, password... 등의 필드가 존재하지만, username을 이용하여 로그인을 할 수 있게 코드를 작성하였다. 하지만 요즘은 대부분 email로 대부분의 도메인에 로그인 할 수 있는 기능이 있기 때문에 username보다는 email로 로그인하는 것이 더 유용할 것이다.

🍃 이메일을 이용한 로그인

🌱 username 로그인

def login_view(request):
    msg = None
    is_ok = False
    if request.method == "POST":
        form = AuthenticationForm(request, request.POST)
        template = "login.html"
        if form.is_valid():
            username = form.cleaned_data.get("username")
            raw_password = form.cleaned_data.get("password")
            user = authenticate(username=username, password=raw_password)
            if user is not None:
                login(request, user)
                template = "index.html"
                is_ok = True
        else:
            msg = "올바른 유저ID와 패스워드를 입력하세요."

    else:
        form = AuthenticationForm()
    
    for visible in form.visible_fields():
        visible.field.widget.attrs["placeholder"] = "유저ID" if visible.name == "username" else "패스워드"
        visible.field.widget.attrs["class"] = "form-control"
    return render(request, "login.html", {"form": form, "msg": msg, "is_ok": is_ok})

✔️ username, password 만을 이용하여 로그인 할때는 AuthenticationForm()을 이용했다. AuthenticationForm()에는 기본적으로 username, password를 번들로 제공하기 때문에 사용 가능한 방법이었다.

✔️ 하지만 email을 이용하여 로그인을 구현하기 위해선 AuthenticationForm()에 없는 email에 대한 필드가 있어야 하기 때문에 내가 정의한 Form으로 AuthenticationForm()을 대체할 생각이다.

🌱 forms>form.py

# This is Form Login Form
class LoginForm(forms.Form):
    email = forms.CharField(
        max_length=100, required=True, widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "이메일"})
    )
    password = forms.CharField(
        max_length=30, required=True, widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "패스워드"})
    )
    remember_me = forms.BooleanField(
        widget=forms.CheckboxInput(attrs={"class": "custom-control-input", "id": "_loginRememberMe"}),
        required=False,
        disabled=False,
    )

✔️ 회원가입에 사용하였던 form.py에 LoginForm을 작성해 주었다. 필드는 email, password, remember_me 3가지이며, remember_me는 나중에 브라우저가 닫혀도 로그인을 유지할 수 있게 사용할 checkbox에 대한 form 필드이다.

❗️❗️ AuthenticationForm인 경우에는 form에 대한 class나 placeholder과 같은 속성을 적용할때 for 루프로 필드마다 각각 부여했지만, LoginForm은 상속받은 forms.Form에서 오버라이딩 된 widget을 이용하여 class나 placeholder를 따로 부여할 수 있다.

help_text의 경우도 widget에 상속되어 있어 사용할 필요 없다.

🌱 email 로그인

def login_view(request):
    is_ok = False
    if request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data.get("email")
            raw_password = form.cleaned_data.get("password")
            remember_me = form.cleaned_data.get("remember_me")
            msg = "올바른 유저ID와 패스워드를 입력하세요."
            try:
                user = Users.objects.get(email=email)
            except Users.DoesNotExist:
                pass
            else:
                if user.check_password(raw_password):
                    msg = None
                    login(request, user)
                    is_ok = True
                    request.session["remember_me"] = remember_me
                    
                    # 브라우저가 닫혔을 때, 세션 만료 시간 설정(edge에서 테스트 진행)
                    # if not remember_me:
                        # request.session.set_expirey(1)
    else:
        msg = None
        form = LoginForm()
    print("REMEMBER_ME: ", request.session.get("remember_me"))
    return render(request, "login.html", {"form": form, "msg": msg, "is_ok": is_ok})

✔️ AuthenticationForm()이 내가 작성한 LoginForm() 으로, form에 대한 유효성 체크 시 usernameemail로 변경해 주었다.

✔️ authenticate()함수로 자격증명이 된 user객체를 생성하였다면 이번에는 직접 ORM을 이용하여 email에 대한 user 객체를 불러왔다.

✔️ try except else를 이용하여 해당 email의 정보를 가진 계정이 존재하지 않으면 except로 넘어갈 수 있게 하며, 계정이 존재하는 경우에는 user 계정에 대한 password가 부합하는지 check_password()를 이용하여 True가 반환되었을 때 login 이 될 수 있게 코드를 작성해 주었다.

✔️ remember_me에대한 내용은 추후 다시 다루려고 한다.

❗️❗️ Caution
try except else로 분기 처리를 하게 된 이유는 user에 대한 객체를 조회 할때 get()을 사용하였는데 queryset조회 시 해당하는 정보가 없으면 api가 그대로 죽어버리기 때문에 try except를 걸어 에러발생시에도 로직의 방향을 핸들링해주었다.

💡 Tip
'유저 아이디가 없습니다.' OR '가입된 유저가 아닙니다.' OR '해당 이메일을 찾을 수 없습니다.' 와 같은 문구는 보안상의 이슈로 사용하지 않는 추세이다!

🗣 개인적으로 사용자에게 어떠한 이유로 로그인이 되지 않았는지 문구를 알려주는 것이 좋다고 판단하고 있었는데, 보안상의 측면에서 나쁜의도를 가지고 찾아볼 수 있다고 하니 너무 상세한 안내문구는 또 다른 문제를 발생할 수 있겠구나 라는 생각이 들었다.


➤ 기타 사항


✔️ 참고로 위의 코드에서 로그인 완료 시 session을 이용하여 로그인 세션 만료에 대한 설정 코드를 작성해 놓았는데, 주석을 풀어 실행시키는 경우 위와 같이 브라우저에서없는 set_expirey라며 사용이 안되는 것을 확인 할 수 있다.

✔️ 이는 Chrome, Edge 등의 브라우저에서 session을 이용해서 만료에 대한 설정을 할 수 없게 되어 있는데, 이는 Django 특성상 하기 그렇다고 한다. 하지만 구현하는 방법은 다시 한 번 다룰 생각이니 지금은 넘어가도록 하자.

profile
인생 개발자 라곰!!

0개의 댓글