728x90

장고(Django) 사용자 인증 테스트 하면서 제대로 이해 못해서 삽질하다 기능 구현에 성공했다.

RSA 암호화/복호화 처리하는 코드는 배제하고 URL Redirection 처리 구현 목적으로 테스트했다.

장고에서 기본 제공하는 Custom User Model은 https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example 을 참고하면 된다.

 

로그인이 안되어 있으면 로그인 화면으로 이동하도록 하는 옵션을 설정한다.

login_url 과 redirect_field_name 을 추가 해준다.

#--- ListView
class PostLV(LoginRequiredMixin,ListView):
    model = Post
    template_name = 'blog/post_all.html'
    context_object_name = 'posts'
    paginate_by = 2
    login_url = '/login/'
    redirect_field_name = 'redirect_to'
 

Mixin 클래스 : 자신의 인스턴스를 만드는 용도보다는 다른 클래스에게 부가 기능을 제공하기 위한 용도로 사용되는 클래스를 의미한다.

 

forms.py

class UserLoginForm(forms.Form):
    username = forms.CharField(
        max_length=32, label='userID',
        widget=forms.TextInput(
            attrs={
                "placeholder""Username",
                "class""form-control"
            }
        ))
    password = forms.CharField(
        label='비밀번호',
        widget=forms.PasswordInput(
            attrs={
                "placeholder""Password",
                "class""form-control"
            }
        ))
 
    def clean(self):
        if self.is_valid():
            username = self.cleaned_data.get('username')
            password = self.cleaned_data.get('password')
            if not authenticate(username=username, password=password):
                raise forms.ValidationError("입력 정보를 확인하세요.")
 

 

 

https://swarf00.github.io/2018/12/10/login.html 를 자세히 읽어보지 않고

대충 복사/붙여넣기 했더니 원하는데로 동작되지 않는다.

# accounts/views.py
from django.conf import settings
from django.contrib.auth import authenticate, login, logout, REDIRECT_FIELD_NAME
from django.contrib.auth.views import SuccessURLAllowedHostsMixin
from django.contrib.sites.shortcuts import get_current_site
from is_safe_url import is_safe_url
from django.urls import reverse_lazy, reverse
from django.views.decorators.cache import never_cache
from django.views.decorators.debug import sensitive_post_parameters
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView, FormView
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, resolve_url
from .forms import SignUpForm, LoginForm, UserLoginForm
from .RSACipher import *
from .models import User
# from django.contrib.auth.models import User
 
class UserLoginView(SuccessURLAllowedHostsMixin,FormView):
    template_name = 'accounts/userlogin.html'
    form_class = UserLoginForm
    redirect_field_name = REDIRECT_FIELD_NAME
    redirect_authenticated_user = False
    authentication_form = None
    extra_context = None
    # success_url = reverse_lazy("home")
 
    @method_decorator(sensitive_post_parameters())
    @method_decorator(csrf_protect)
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        if self.redirect_authenticated_user and self.request.user.is_authenticated:
            redirect_to = self.get_success_url()
            if redirect_to == self.request.path:
                raise ValueError(
                    "Redirection loop for authenticated user detected. Check that "
                    "your LOGIN_REDIRECT_URL doesn't point to a login page."
                )
            return HttpResponseRedirect(redirect_to)
        return super().dispatch(request, *args, **kwargs)
 
    def get_success_url(self):
        url = self.get_redirect_url()
        print("get_success_url : {}".format(url))
        return url or resolve_url(settings.LOGIN_REDIRECT_URL)
 
    def get_redirect_url(self):
        redirect_to = self.request.POST.get(
            self.redirect_field_name, # 1. 폼의 필드 중 next 이름을 가진 필드 값
            self.request.GET.get(self.redirect_field_name, '')
            # 2. query parameter 중 next 이름을 가진 값
        )
        url_is_safe = is_safe_url(
            url=redirect_to,
            allowed_hosts=self.get_success_url_allowed_hosts(),
            require_https=self.request.is_secure(),
        )
        return redirect_to if url_is_safe else ''
 
    def form_valid(self, form):
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password')
        user = authenticate(self.request, username=username, password=password)
        if user is not None and user.is_active:
            login(self.request,user)
        return super().form_valid(form)
 
 

 

 

로그인하면 Home 화면으로 무조건 이동하는 것은 아래와 같이 구현하면 된다.

# accounts/views.py
from django.contrib.auth import authenticate, login, logout, REDIRECT_FIELD_NAME
from django.contrib.auth.views import SuccessURLAllowedHostsMixin
from django.urls import reverse_lazy, reverse
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView, FormView
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect, resolve_url
from .forms import SignUpForm, LoginForm, UserLoginForm
from .RSACipher import *
from .models import User
# from django.contrib.auth.models import User
 
 
class UserLoginView(SuccessURLAllowedHostsMixin,FormView):
    template_name = 'accounts/userlogin.html'
    form_class = UserLoginForm
    success_url = reverse_lazy("home")
 
    def form_valid(self, form):
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password')
        user = authenticate(self.request, username=username, password=password)
        if user is not None and user.is_active:
            login(self.request,user)
        return super().form_valid(form)
 

 

게시글 List를 클릭할 때 인증되어 있지 않으면 인증 URL 로 이동하고, 인증 완료후 원래 게시글 List 화면으로 이동하는 기능을 구현하려고 엄청 삽질을 좀 했다.

세션 처리를 하면 금방 해결될 사항이었는데 말이다.

# accounts/views.py
from django.conf import settings
from django.contrib.auth import authenticate, login, logout, REDIRECT_FIELD_NAME
from django.urls import reverse_lazy, reverse
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView, FormView
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect, resolve_url
from .forms import SignUpForm, LoginForm, UserLoginForm
from .models import User
# from django.contrib.auth.models import User
 
 
class UserLoginView(FormView):
    template_name = 'accounts/userlogin.html'
    form_class = UserLoginForm
    # success_url = reverse_lazy("home")
 
    def form_valid(self, form):
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password')
        user = authenticate(self.request, username=username, password=password)
        if user is not None and user.is_active:
            login(self.request,user)
        return super().form_valid(form)
 
    def get_context_data(self**kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.GET.get("redirect_to"):
            redirect_to = self.request.GET.get("redirect_to")
            self.request.session['redirect_to'= redirect_to
        return context
 
    def get_success_url(self):
        url = self.request.session.get('redirect_to')
        return url or resolve_url(settings.LOGIN_REDIRECT_URL)
 

ㅇ View : 모든 클래스형 뷰의 기본이 되는 최상위 뷰. 모든 클래스형 뷰는 이 View 클래스를 상속받는다.

ㅇ TemplateView : 단순하게 화면에 보여줄 템플릿 파일을 처리하는 정도의 간단한 뷰

ㅇ FormView : 폼을 보여주기 위한 뷰. form_class, template_name, success_url 속성 필요하다.

   만약 검색 결과를 같은 페이지에서 보여주고자 한다면, success_url 속성 지정은 생략한다.

   form_class 는 FormView, CreateView, UpdateView 에서 사용한다.

ㅇ CreateView : 새로운 레코드를 생성해서 테이블에 저장해주는 뷰. FormView의 기능을 포함하고 있다.

    폼을 만들 때 사용할 필드를 fields 속성으로 정의한다.

    fields 는 CreateView, UpdateView 에서 사용한다.

ㅇ get_context_data(**kwargs) :  모든 제네릭 뷰에서 사용하는 메소드이다.

    템플릿에서 사용할 context 데이터를 반환한다.

    뷰에서 템플릿 파일에 넘겨주는 context 데이터를 추가하거나 변경할 수 있다.

ㅇ 모델 폼(ModelForm) : 모델에 정의한 필드를 참조해서 모델 폼을 만드는 역할을 한다.

 

 

728x90
블로그 이미지

Link2Me

,