장고 접근 제어
뷰 접근 제어
decorator 는 함수형 뷰에 사용하고
mixin 은 클래스형 뷰에 사용한다.
둘다 템플릿이 렌더되는 것을 통제해 유저가 페이지에 접근하는 것을 제어한다.
request처리 과정
어떤 url에 대해 요청이 들어오면 장고는 url을 보고 적절한 view로 보내준다. 이 부분을 url dispatcher라고 한다.
url dispatcher에서 뷰로 요청을 보내면 뷰에서 처리를 하고 응답을 한다.
이때 뷰로 넘어가기 전에 mixin/decorator를 먼저 거치게 해서 mixin/decorator를 통과하면 뷰로 넘어가고 실패하면 뷰로 넘어가지 않고 실패시의 로직을 따르게 만든다.
mixin
django-braces는 접근 제어에 관련된 mixin들을 제공한다.
이런 것을 acesss mixin이라 한다.
pip install django-braces
django-braces를 설치하고 사용할 수 있다.
LoginRequiredMixin
LoginRequiredMixin은 로그인이 되어있는 유저만 해당 페이지에 접근할 수 있게 한다.
from braces.views import LoginRequiredMixin
class ReviewCreateView(LoginRequiredMixin, CreateView):
...
access mixin은 반드시 제네릭 뷰 왼쪽에 작성한다.
여러 클래스를 상속받을 때는 왼쪽부터 오른쪽으로 진행되기 때문이다.
웹서비스의 로그인에 대한 url을 설정해야 한다.
장고 기본 로그인 url을 사용한다면
settings에 LOGIN_URL = ‘account_login’ 을 작성하면 된다.
LoginRequiredMixin은 로그아웃 상태일 때 위에 작성한 url로 리디렉트한다.
로그인을 한 후에는 가려고 했던 페이지로 리디렉트 된다.
UserPassesTestMixin
UserPassesTestMixin은 충족해야 하는 조건을 직접 정의한다.
직접 정의한 test_func를 통과할 때만 뷰로 접근하게 만든다.
test_func는 뷰에 접근할 수 있으면 True, 아니면 False를 리턴한다.
path(
'email-confirmation-required/',
TemplateView.as_view(template_name="account/email_confirmation_required.html"),
name='account_email_confirmation_required'
),
urls.py에서 페이지를 만들어 준다.
from braces.views import LoginRequiredMixin, UserPassesTestMixin
from allauth.account.models import EmailAddress
from coplate.functions import confirmation_required_redirect
class ReviewCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
...
redirect_unauthenticated_users = True
raise_exception = confirmation_required_redirect
...
def test_func(self, user):
return EmailAddress.objects.filter(user=user, verified=True).exists()
Mixin의 순서를 원하는 로직에 맞게 잘 배치해야 한다.
test_func에 접근에 필요한 조건을 작성한다.
allauth는 이메일을 EamilAddress모델에 저장한다.
그 중에서 현재 사용자에 등록이 되어있고(user=user)
인증이 완료된 주소가(verified=True)
하나라도 있는지(exists) 확인하는 코드다.
redirect_unauthenticated_users
redirect_unauthenticated_users=True 는
뷰 접근이 차단된 유저 중에, 로그인이 되어있는 유저와 로그인이 되어있지 않은 유저를 다르게 처리할 것인지의 코드다.
True로 하면 로그인이 안 된 유저는 로그인 페이지로, 로그인 된 유저는 raise_exception에 따라 처리한다.
False는 모두 raise_exception에 따라 처리한다.
raise_exception
raise_exception 은
True를 주면 접근할 수 없는경우 403에러를 내고 커스텀 함수로 주면 그 함수를 그대로 실행한다.
커스텀 함수의 파라미터는 self, reqeust를 준다.
from django.shortcuts import redirect
from allauth.account.utils import send_email_confirmation
def confirmation_required_redirect(self, request):
send_email_confirmation(request, request.user)
return redirect('account_email_confirmation_required')
이렇게 커스텀 함수를 작성한다.
send_email_confirmation 는 allauth가 제공하는 이메일을 보내는 함수다.
이메일을 보낸 후 원하는 페이지로 리디렉트 시킨다.
해당 유저의 글만 수정/삭제
{% if review.author == user %}
이렇게 if문을 사용해 글이 해당 유저의 글일 때만 수정/삭제 버튼이 나오도록 작성해서 해당 유저만 글을 수정/삭제하도록 만든다.
하지만 이렇게 버튼을 누르지 않아도 url로 접근하면 수정할 수 가 있게된다. 이 부분을 방지하려면 수정/삭제 뷰에서
LoginRequiredMixin, UserPassesTestMixin을 추가하고
raise_exception = True
redirect_unauthenticated_users = False
def test_func(self, user):
review = self.get_object()
return review.author == user
를 작성한다.
test_func함수는 조건을 충족하는지 확인하기 위해 쓴다.
self.get_object로 글을 가져오고 작성자와 유저가 일치하는 지 확인한다.
일치하지 않을 때의 처리는 raise_exception = True를 해서 403을 리턴하게 한다.
웹사이트에서 버튼을 눌러 정상적인 접근을 하지 않고 url로 부적절한 접근을 한것이기 때문에 403을 리턴하면 된다.
redirect_unauthenticated_users는 기본값이 False이므로 생략해도 된다.
이렇게 작성했을 때 로그인이 안 됀 상태에서 수정/삭제 페이지로 접근하거나 본인이 작성한 글이 아닌데 접근하는 경우 모두 403을 발생시킨다.
decorator
decorator는 django.contrib.auth에서 가져온다.
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
login_required는 LoginRequiredMixin과 비슷한 기능이다.
마찬가지로 settings.py에 LOGIN_URL을 작성하면 로그인이 안됐을 때 작성한 페이지로 리디렉트 된다.
# views.py
def my_view(request):
...
# urls.py
from django.contrib.auth.decorators import login_required
from .views import my_view
urlpatterns = [
path('my/url/', login_required(my_view), name='my_url'),
decorator는 이렇게 url패턴을 정의할 때 사용할 수 도 있다.
user_passes_test는 UserPassesTestMixin과 비슷한 기능이다.
다만 뷰에 접근하지 못하는 유저를 어떤 URL로 리디렉트하는지 밖에 구현할 수 없다.
Leave a comment