我已经看到了许多关于如何在石墨烯中实现许可系统的讨论,但是除了这些讨论之外,还没有看到任何确定的实际结果。有关该主题的一些讨论示例如下:
不幸的是,这些都不是推荐在石墨烯中实现权限的首选方法。有谁知道这样做的最佳实践是什么?
答案 0 :(得分:0)
首先,仅当公共接口与私有接口有显着差异时,才将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
语句检查多个权限,请在@required_permission
装饰器中使用lambda:
@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