mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-13 17:52:19 +03:00
fix #79 add decorator has_perms for nodes
This commit is contained in:
parent
5d6c7f2dc3
commit
320d95333f
|
@ -108,3 +108,28 @@ method to your ``DjangoObjectType``.
|
|||
if post.published or context.user == post.owner:
|
||||
return post
|
||||
return None
|
||||
|
||||
|
||||
Permission node access
|
||||
----------------------
|
||||
|
||||
For restrict access using permissions, use the `has_perm` decorator in node.
|
||||
|
||||
.. code:: python
|
||||
|
||||
from graphene_django.types import DjangoObjectType
|
||||
from graphene_django.decorator import has_perms
|
||||
from .models import Post
|
||||
|
||||
class PostNode(DjangoObjectType):
|
||||
class Meta:
|
||||
model = Post
|
||||
only_fields = ('title', 'content')
|
||||
interfaces = (relay.Node, )
|
||||
|
||||
@has_perms(["django_app.django_can_see_content_permission"])
|
||||
def resolve_content(self, id, context, info):
|
||||
return self.content
|
||||
|
||||
|
||||
|
||||
|
|
51
graphene_django/decorators.py
Normal file
51
graphene_django/decorators.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
# coding: utf-8
|
||||
from functools import wraps
|
||||
from django.http import HttpResponseForbidden
|
||||
|
||||
|
||||
def has_perms(permissions):
|
||||
"""
|
||||
Check if have user logged and permissions to see some value
|
||||
|
||||
Example:
|
||||
class CityNode(DjangoObjectType):
|
||||
class Meta(object):
|
||||
interfaces = (relay.Node,)
|
||||
model = City
|
||||
only_fields = (
|
||||
'name', 'locality', 'slug', 'state', 'active',
|
||||
)
|
||||
|
||||
@has_perms(["django_city_app.can_see_location"])
|
||||
def resolve_location(self, args, context, info):
|
||||
return self.locality.pos
|
||||
|
||||
Args:
|
||||
permissions: ["django_app.permission_codename",]
|
||||
"""
|
||||
def decorator(method):
|
||||
if callable(permissions):
|
||||
method.permissions = []
|
||||
else:
|
||||
method.permissions = permissions
|
||||
|
||||
@wraps(method)
|
||||
def wrapper(*args, **kwargs):
|
||||
context = kwargs.get('context', dict(zip(method.func_code.co_varnames,
|
||||
args)).get('context', None))
|
||||
if not context:
|
||||
return HttpResponseForbidden('Forbidden. No context, no access.')
|
||||
try:
|
||||
user = context.user
|
||||
except AttributeError:
|
||||
return HttpResponseForbidden('Forbidden. No request.')
|
||||
|
||||
if method.permissions and not user.has_perms(method.permissions):
|
||||
return HttpResponseForbidden('Forbidden. User without access')
|
||||
return method(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
if callable(permissions):
|
||||
return decorator(permissions)
|
||||
|
||||
return decorator
|
80
graphene_django/tests/test_decorators.py
Normal file
80
graphene_django/tests/test_decorators.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
# encoding: utf-8
|
||||
from django.utils.unittest import TestCase
|
||||
from ..decorators import has_perms
|
||||
|
||||
|
||||
class MockContext(object):
|
||||
def __init__(self, authenticated=True, is_staff=False, superuser=False, perms=[]):
|
||||
self.user = self
|
||||
self.authenticated = authenticated
|
||||
self.is_staff = is_staff
|
||||
self.is_superuser = superuser
|
||||
self.perms = perms
|
||||
self.status_code = 200
|
||||
|
||||
def is_authenticated(self):
|
||||
return self.authenticated
|
||||
|
||||
def has_perms(self, check_perms):
|
||||
for perm in check_perms:
|
||||
if perm not in self.perms:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class TestHasPermsDecorator(TestCase):
|
||||
|
||||
@classmethod
|
||||
@has_perms(['django_app.dummy_permission'])
|
||||
def check_user_perms_func(cls, input, context, info=None):
|
||||
cls.status_code = 200
|
||||
cls.content = True
|
||||
return cls
|
||||
|
||||
def test_get_content_without_permission(self):
|
||||
context = MockContext(
|
||||
authenticated=True
|
||||
)
|
||||
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||
self.assertEqual(request.status_code, 403)
|
||||
self.assertEqual(request.content, 'Forbidden. User without access')
|
||||
|
||||
def test_get_content_without_authentication(self):
|
||||
context = MockContext(
|
||||
authenticated=False
|
||||
)
|
||||
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||
self.assertEqual(request.status_code, 403)
|
||||
self.assertEqual(request.content, 'Forbidden. User is not authenticated.')
|
||||
|
||||
def test_get_context_with_permission(self):
|
||||
context = MockContext(
|
||||
authenticated=True,
|
||||
perms=['django_app.dummy_permission']
|
||||
|
||||
)
|
||||
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||
self.assertEqual(request.status_code, 200)
|
||||
self.assertEqual(request.content, True)
|
||||
|
||||
def test_get_context_with_diffent_and_valid_permission(self):
|
||||
context = MockContext(
|
||||
authenticated=True,
|
||||
perms=['another_app.dummy_permission',
|
||||
'django_app.dummy_permission']
|
||||
|
||||
)
|
||||
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||
self.assertEqual(request.status_code, 200)
|
||||
self.assertEqual(request.content, True)
|
||||
|
||||
def test_get_context_with_diffent_and_invalid_permission(self):
|
||||
context = MockContext(
|
||||
authenticated=True,
|
||||
perms=['another_app.dummy_permission',
|
||||
'another_app.dummy_permission2']
|
||||
|
||||
)
|
||||
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||
self.assertEqual(request.status_code, 403)
|
||||
self.assertEqual(request.content, 'Forbidden. User without access')
|
Loading…
Reference in New Issue
Block a user