jc.jang

16강 Permission 시스템을 통한 사용자 접근 제한하기 본문

Django/Django - 인증편

16강 Permission 시스템을 통한 사용자 접근 제한하기

jangstory 2019. 9. 9. 03:03

주제

  • Permission 시스템을 통한 사용자 접근 제한하기

노트

  • 특정 User/Group에 Permission을 할당할 수 있다.
  • admin 페이지에 각 User/Group 별로 Permission 할당 UI가 제공된다.
  • 모델별로 퍼미션 지정이 가능하다.
    • 디폴트 퍼미션 제공: 추가, 수정, 삭제
  • admin 페이지에서 유저 클릭 후 권한 탭에서 사용자 권한을 확인, 부여할 수 있다.
  • 사용자 권한을 부여하는 것과 별개로, 뷰에서 관련 로직을 따로 처리해줘야한다.
    • 예를 들어, A라는 사용자에게 'can delete post' 권한을 준다고해서 post를 삭제할 수 있는건 아님

 

  • 실제 상황에서 어떻게 쓰이는지 알아보자.
  • 미션 - 로그인 여부를 먼저 검증하고, 로그인 유저가 GoldUser가 아닐 경우 등급 업그레이드 안내 페이지 보여주기

 

  1. goldmembership_guide 페이지 만들기
  2. blog.can_view_goldpage 권한 추가하기
  3. 뷰에 blog.can_view_goldpage 권한 제한하기
  4. 유저 혹은 그룹에 blog.can_view_goldpage 권한 부여하기

 

  • 먼저 골드멤버가 아닐 경우, 골드 멤버십을 안내하는 페이지를 만든다.
  • blog/urls.py
from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    # ...
    path('<int:pk>/', views.post_detail, name='post_detail'),
    path('goldmembership_guide/', views.goldmembership_guide, name='goldmembership_guide')
]

 

  • blog/views.py
def goldmembership_guide(request):
    return render(request, 'blog/goldmembership_guide.html')

 

  • blog/templates/blog/goldmembership_guide.html
{% extends "blog/layout.html" %}

{% block content %}
    <h2>골드 멤버 가이드</h2>
    골드 멤버만 접근할 수 있습니다.
    골드 멤버가 되고 싶으면 댓글을 10번 이상 작성해야합니다.
{% endblock %}
  • 위와 같이골드 멤버십을 안내하는 페이지를 작성한다.

 

  • 그 다음으로 can_view_goldpage 권한을 추가한다.
from django.db import models
from django.shortcuts import reverse

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        permissions = [
            ('can_view_goldpage', 'Can View Goldpage')
        ]

    def __str__(self):
        return self.title
        
    def get_absolute_url(self):
        return reverse("blog:post_detail", kwargs={"pk": self.pk})
    
  • Model의 Meta 클래스에는 상당히 많은 설정들이 가능하다.
  • 그 중 permissions 필드를 재정의한다.
  • 리스트안에 리스트 혹은 튜플로 데이터를 할당하고 첫번째 인자는 permisson_code, 두번째 인자는 human_readable_permission_name이다.
  • 이렇게 작성하고 반드시 migrate를 해야한다. (실제로는 데이터베이스에 변경사항은 없음)

 

  • 이제 우리가 만든 권한을 뷰에 적용한다.
  • @permission_required(링크) 데코레이터를 활용하여 뷰를 다시 작성한다.
from django.urls import reverse_lazy
from django.shortcuts import render
from .models import Post
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import permission_required

@login_required
@permission_required('blog.can_view_goldpage', login_url=reverse_lazy('blog:goldmembership_guide'))
def post_detail(request, pk):
    post = Post.objects.get(pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})
  • 데코레이터를 두가지 사용했다.
  • 먼저, 사용자가 로그인했는지 확인하기 위해 @login_required 데코레이터를 사용했고, 로그인한 사용자라면 blog.can_view_goldplage 권한이 있는지 확인하기 위해 @permission_required 데코레이터를 사용했다.
  • 파라미터에 대한 자세한 설명은 위에 링크를 걸어 놓은 공식 문서에서 확인 가능하다.
  • login_url은 권한이 없는 경우 이동할 페이지로 생각하면 된다.

 

  • 마지막으로, 유저에게 권한을 부여하자.
python manage.py shell

>>> from django.contrib.auth import get_user_model
>>> user = get_user_model().objects.all().last()

>>> from django.contrib.contenttypes.models import ContentType
>>> from blog.models import Post
>>> content_type = ContentType.objects.get_for_model(Post)

>>> from django.contrib.auth.models import Permission
>>> permission = Permission.objects.get(codename='can_view_goldpage',content_type=content_type,)
>>> user.user_permissions.add(permission)
>>> user.has_perm('blog.can_view_goldpage')
False

>>> user = get_user_model().objects.all().last()
>>> user.has_perm('blog.can_view_goldpage')
True
  • 이렇게 쉘에 진입하여 권한 부여가 가능하다. 혹은 admin 페이지의 권한 탭에서 UI를 이용하여 할 수도 있다.
  • 그런데 코드에서 이상한 부분이 있다.
  • user.user_permissions.add(permission)을 통해 권한을 부여하고 권한을 확인했더니 False가 반환되었다.
  • 이것은 권한 캐싱(링크)때문이다.
  • 사용자에 대해 처음 얻은 권한 정보를 캐싱하여 사용하므로, 권한을 추가한 후 바로 확인하는 경우 가장 쉬운 해결책은 데이터베이스에서 사용자를 다시 읽어오는 것이다.

질문

  • medium이라는 온라인 출판 플랫폼을 이용하다 보면, '포스트를 무료로 확인할 수 있는 횟수를 모두 사용하였습니다.'와 같은 문구를 본 적이 있다. 이러한 기능을 구현하려면 어떻게 해야할까?

요약

  • permission을 통해 사용자 권한을 부여할 수 있다.
  • permission을 부여한 것과 별개로 view에서 처리하는 로직이 필요하다.
  • permission caching을 사용하기 때문에 권한을 추가한 후 바로 확인하는 경우에는 사용자를 다시 읽어와야한다.

날짜

  • 오전 2시, 20190919

 

Comments