首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在graphene中分离公共和私有API的推荐最佳实践是什么?

在graphene中分离公共和私有API的推荐最佳实践是什么?
EN

Stack Overflow用户
提问于 2019-09-25 07:02:38
回答 1查看 919关注 0票数 5

我见过许多关于如何在石墨烯中实施许可制度的讨论,但除了这些讨论之外,我没有看到任何明确的实际结果。关于这一专题的一些讨论实例如下:

不幸的是,所有这些都不推荐在石墨烯中实现权限的首选方法。有没有人知道目前做这件事的最佳做法是什么?

EN

回答 1

Stack Overflow用户

发布于 2019-10-25 19:47:06

首先,只有当公共接口与私有接口有很大区别时,才能将API端点拆分为公共/私有端点。否则,您将面临代码问题中的冗余。

在我们的项目中,我们提出了一个简单的解决方案,它似乎被许多人认为是理想的解决方案。

我们在resolve方法上使用了以下修饰器:

代码语言:javascript
复制
# 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

您可以如下所示使用此装饰器:

代码语言:javascript
复制
# 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,您将得到以下响应:

代码语言:javascript
复制
{
  "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装饰器中使用lambdas:

代码语言:javascript
复制
@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
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58092792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档