我已经看到了许多关于如何在石墨烯中实施许可系统的讨论,但除了这些讨论之外,还没有看到任何明确的实际结果。关于该主题的一些讨论示例如下:
不幸的是,这些都没有推荐在石墨烯中实现权限的首选方法。有谁知道目前这样做的最佳做法是什么?
我已经看到了许多关于如何在石墨烯中实施许可系统的讨论,但除了这些讨论之外,还没有看到任何明确的实际结果。关于该主题的一些讨论示例如下:
不幸的是,这些都没有推荐在石墨烯中实现权限的首选方法。有谁知道目前这样做的最佳做法是什么?
首先,只有当公共接口与私有接口显着不同时,将 API 端点拆分为公共/私有才有意义。如果不是,那么您将面临代码问题的冗余。
在我们的项目中,我们提出了简单的解决方案,这似乎被许多人认为是所需的解决方案。
我们在方法上使用以下装饰器resolve
:
# decorators.py
def permission_required(permission):
""" Checking permissions on per method basis. """
def wrapped_decorator(func):
def inner(cls, info, *args, **kwargs):
if check_permission(permission, info.context):
return func(cls, info, **kwargs)
raise Exception("Permission Denied.")
return inner
return wrapped_decorator
def check_permission(permission, context):
"""
Helper function to resolve permissions.
Permission can be a string "app_name.perm_codename"
or callable (lambda) function with user passed as an argument:
example: lambda(user): user.username.startswith('a')
"""
if callable(permission):
if not permission(context.user):
return False
else:
if not context.user.has_perm(permission):
return False
return True
您可以按如下方式使用此装饰器:
# schema.py
from . decorators import permission_required
class UserNode(DjangoObjectType):
class Meta:
model = User
interfaces = (relay.Node,)
only_fields = (
'id', 'first_name', 'last_name',
'email', 'username'
)
filter_fields = {
'username': ['exact'],
'id': ['exact'],
}
role = graphene.String(description="User's role in the system.")
@permission_required('our_app.some_perm')
def resolve_role(self, info, **kwargs):
if info.context.user.username in ['dev1', 'dev2']:
return "developer"
if info.context.user.is_superuser:
return "admin"
if info.context.user.is_staff:
return "staff"
return "guest"
如果您没有此特定权限our_app.some_perm
,您将收到以下响应:
{
"errors": [
{
"message": "Permission Denied.",
"locations": [
{
"line": 7,
"column": 9
}
],
"path": [
"userSet",
"edges",
0,
"node",
"role"
]
},
{
"message": "Permission Denied.",
"locations": [
{
"line": 7,
"column": 9
}
],
"path": [
"userSet",
"edges",
1,
"node",
"role"
]
}
],
"data": {
"userSet": {
"edges": [
{
"node": {
"id": "VXNlck5vZGU6MQ==",
"username": "user1",
"role": null
}
},
{
"node": {
"id": "VXNlck5vZGU6Mg==",
"username": "user2",
"role": null
}
}
]
}
}
}
当您需要更富有表现力的方式来检查权限时,例如使用语句检查多个权限时,请在装饰器or
中使用 lambda :@required_permission
@permission_required(lambda u: u.has_perm('app.perm1') or u.has_perm('app.perm2'))
def resolve_something1(self, info, **kwargs):
# ... do your stuff here
return data
@permission_required(lambda user: user.username.startswith('a'))
def resolve_something2(self, info, **kwargs):
# ... do your stuff here
return data