ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Django) User 아이디 찾기, 비밀번호 찾기(초기화) 페이지 만들기
    Django 2019. 7. 12. 14:36

    회원가입, 로그인, 로그아웃의 기능을 갖추었다면, 가입한 회원이 자신의 아이디, 비밀번호를 찾을 수 있는 기능이 필요하다..

    Django는 물론 비밀번호 찾기를 지원한다. 하지만 이걸 다루는 글을 찾지 못해 헤맨 나와 같은 사람들을 위해 적어보려 한다.

     

    Django의 기본 비밀번호 찾기 같은 경우 사용자가 가입할 때 입력한 email을 입력하면 비밀번호를 초기화할 수 있는 링크를 해당 email로 보내준다. Django의 기본 회원가입의 경우 username, email, password를 입력받기 때문에 기본 기능을 이용하면 충분히 활용이 가능하다.

    하지만 내가 만드는 중인 페이지는 이메일을 입력받지 않아 어떻게 주어진 class를 수정해야 할지 막막했다.

    그러던 중 '내 페이지는 회원가입 시 Google ID를 입력받는데 뒤에 @gmail을 붙여 DB에 email로 저장하고, 계정 정보를 찾을 때 Google ID를 입력받고, 그 뒤에 @gmail을 붙여서 이용하면 되지 않을까?' 하는 생각이 들어 직접 해보니 성공이었다.

     

    먼저 Email 발송을 위해 setting.py 파일을 열어 다음과 같이 수정해주자.
    아래의 코드는 Google 계정을 기준으로 작성하였고, 다른 플랫폼을 사용한다면 구글에 Django 네이버 메일 등으로 검색해 보면 된다.

    아마 시도를 해보면 이메일 발송을 실패할 텐데. Google 계정의 보안 설정 때문이다. 이 또한 구글에 검색해 보자. 약간의 설정만 변경해 주면 된다.

    EMAIL_HOST = 'smtp.gmail.com'
    # 메일을 호스트하는 서버
    EMAIL_PORT = '587'
    # gmail과의 통신하는 포트
    EMAIL_HOST_USER = '구글아이디@gmail.com'
    # 발신할 이메일
    EMAIL_HOST_PASSWORD = '구글비밀번호'
    # 발신할 메일의 비밀번호
    EMAIL_USE_TLS = True
    # TLS 보안 방법
    DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
    # 사이트와 관련한 자동응답을 받을 이메일 주소

    다음의 코드는 Django에서 제공하는 기본적인 User Password Rrset 코드이다. 코드 아래의 설명을 읽어보면 이해가 갈 것이다.

    urls.py

    from django.urls import path
    from django.contrib.auth import views as auth_views
    from . import views
    
    urlpatterns = [
        path('password_reset/', auth_views.PasswordResetView.as_view(), name="password_reset"),
        path('password_reset_done/', auth_views.PasswordResetDoneView.as_view(), name="password_reset_done"),
        path('password_reset_confirm/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name="password_reset_confirm"),
        path('password_reset_complete/', auth_views.PasswordResetCompleteView.as_view(), name="password_reset_complete"),
    ]

    어떤 앱의 urls.py에 넣던지 상관이 없이 작동이 된다.
    먼저 유저가 /password_reset/ 페이지에 접속하여 이메일을 입력하면 PasswordResetView에 의해 입력받은 메일로 초기화 링크가 발송이 되며, 제어가 password_reset_done으로 이동한다.

    유저에게 발송되는 메일은 다음과 같은 형식이다. /password_reset_confirm/<uidb64>/<token>/

    유저는 링크를 클릭하면 password_reset_confirm으로 이동하며 이 페이지에서 비밀번호를 입력하면 비밀번호가 입력한 값으로 변경이 되며 password_reset_complete으로 이동하게 된다.

    기본 password_reset 페이지는 아래와 같다.

    우리들은 사이트 개발자라 이 화면이 괜찮을 수 있지만, 유저는 갑자기 이런 화면으로 이동한다면 상당히 놀랄 것이다.

    본인이 만약 장고에서 제공하는 그대로 이메일 주소를 입력받으려면 Template들만 새로 만들어 주면 된다.

    경로는 본인의 장고프로젝트명/templates/registration 속에 password_reset_form.html, password_reset_confirm.html, password_reset_done.html 파일을 만들어 각 폼에 맞게 수정을 해주면 된다.

     

    하지만 필자처럼 다른 값을 입력받아 email로 처리하기 위해선 약간의 수정들이 필요하다.

    먼저 password_reset부터 손보자. 입력한 urls.py와 같은 경로상에 있는 views.py파일을 열어 다음과 같이 오버 라이딩을 해주자.

    class UserPasswordResetView(PasswordResetView):
        template_name = 'password_reset.html' #템플릿을 변경하려면 이와같은 형식으로 입력
    
        def form_valid(self, form):
            if 본인의UserModel이름.objects.filter(email=self.request.POST.get("email")).exists():
                opts = {
                    'use_https': self.request.is_secure(),
                    'token_generator': self.token_generator,
                    'from_email': self.from_email,
                    'email_template_name': self.email_template_name,
                    'subject_template_name': self.subject_template_name,
                    'request': self.request,
                    'html_email_template_name': self.html_email_template_name,
                    'extra_email_context': self.extra_email_context,
                }
                form.save(**opts)
                return super().form_valid(form)
            else:
                return render(self.request, 'password_reset_done_fail.html')

    우리는 PasswordResetView를 상속받아 그 안의 변수와 함수를 오버 라이딩해준 것이다.

    먼저 필자 같은 경우 장고프로젝트명/templates/registration 속에 template 파일이 있는 것보다, 같은 애플리케이션 내의 templates 폴더 내에 있는 것이 더 직관적이라 생각하여 template_name을 변경해 주었다. 만약 기본 디렉터리를 사용하고 싶다면 저 줄을 지우면 된다.

    장고의 View 같은 경우 성공적으로 폼이 입력이 되어 온다면, form_valid라는 함수가 실행이 되게 된다. 이 함수를 오버 라이딩해주면 우리가 원하는 대로 수정할 수 있다.

    장고의 경우 기본적으로 입력받은 이메일이 존재하던, 하지 않던 메일이 발송이 됐다는 페이지로 이동을 하게 된다. 만약 그렇게 될 경우, 유저는 하염없이 자신의 없는 정보에 대한 메일을 기다리게 될 것이다. 나는 만약 입력받은 이메일에 대한 정보가 없다면, 사용자에게 이를 알려줄 필요가 있다고 생각하여 if 문을 통해 입력된 정보에 대한 값이 없을 경우, 정보가 없다는 안내 페이지로 이동을 하게 만들었다.

    if문의 본인의UserModel이름 부분에 본인이 설계한 UserModel을 넣으면 된다. (from .models import * 를 통해 import를 해주는 걸 잊지 말자)

     

    그리고 urls.py를 다음과 같이 수정해주자.

        path('password_reset/', views.UserPasswordResetView.as_view(), name="password_reset"),
    	#auth_views.PasswordResetView.as_view() 부분을 위와같이 수정

    그러면 해당 url이 우리가 의도한 대로 이동을 할 것이다.

    필자 같은 경우 Google ID를 입력받는데, 이를 JavaScript를 통해 뒤에 '@gmail.com'을 붙여 Input type="hidden"으로 숨겨진 email의 value를 변경해 주는 식으로 문제를 해결했다.

    JavaScript는 다음과 같다.

    <script>
    
            function goData(){
                var form = document.getElementById("frm");
                form.email.value = form.google_id.value+"@gmail.com";
                form.submit();
            }
    
    </script>

    form은 다음과 같다.

    <form id="frm" method="post" class="sign-in-form">
      {%csrf_token%}
      <div>
        구글 ID
        <input type="text" class="form-control" placeholder="google ID"
        id="google_id"
        name="google_id"
        required
        autofocus>
    
        <input type="hidden" class="form-control"
        id="email"
        name="{{ form.email.html_name }}"
        required>
        </div>
        <div>
        <br>
        <button type="button" onclick="goData()" class="form-control btn btn-primary">이메일 발송</button>
      </div>
    </form>

    이렇게 하면 굳이 이메일을 입력받지 않고도, 이메일로 처리를 하여 해당 기능을 이용할 수 있다.

     

    이렇게 class를 오버 라이딩하며 자신이 원하는 대로 사용을 하면 된다.

    참고로 Class 구조를 확인하기 위해선 Finder를 열고 Macintosh HD⁩ ▸ ⁨사용자⁩ ▸ ⁨사용자이름 ▸ ⁨가상환경이름 ▸ ⁨장고프로젝트이름 ▸ ⁨lib⁩ ▸ ⁨python3.7⁩ ▸ ⁨site-packages⁩ 경로로 들어가 from 뒤에 있는 경로로 이동을 해서 파일을 열어보면 된다.

    class를 분석하고 자신이 원하는 대로 오버 라이딩하여 사용하면 본인의 개발 실력을 늘리는 대에도 일조할 수 있을 것이다.

Designed by Tistory.