首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于可访问字段的Graphql Absinthe Elixir权限

基于可访问字段的Graphql Absinthe Elixir权限
EN

Stack Overflow用户
提问于 2017-07-21 11:03:14
回答 2查看 1.5K关注 0票数 3

定义并非所有用户都可以访问的字段的正确方法是什么。

例如,一般用户可以查询用户并找到另一个用户处理,但只有管理员用户才能找到他们的电子邮件地址。用户类型将其定义为字段,但可能无法访问。对于一般用户所能看到的内容,是否应该有单独的类型?你会怎么定义它?

抱歉,如果不是很清楚的话,我只是没有词汇表。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-21 18:02:12

编辑:警告: Graphql文档不同意这种方法。请谨慎使用。在任何需要私有字段的地方,都必须包括适当的中间件。

使用苦艾中间件

这是一些代码,如何做到这一点。在本例中,经过身份验证的用户可以看到电子邮件地址。匿名用户不能。您可以调整逻辑以要求任何您想要的权限。

代码语言:javascript
复制
defmodule MySite.Middleware.RequireAuthenticated do
  @behaviour Absinthe.Middleware

  @moduledoc """
  Middleware to require authenticated user
  """

  def call(resolution, config) do
    case resolution.context do
      %{current_user: _} ->
        resolution
      _ ->
        Absinthe.Resolution.put_result(resolution, {:error, "unauthenticated"})
    end
  end
end

然后定义您的对象:

代码语言:javascript
复制
  object :user do
    field :id, :id
    field :username, :string 
    field :email, :string do
      middleware MySite.Middleware.RequireAuthenticated
      middleware Absinthe.Middleware.MapGet, :email
    end
  end

因此,我们的字段电子邮件受到RequireAuthenticated中间件的保护。但是根据上面的链接

中间件/3的一种用法是在字段中设置默认中间件,替换default_resolver宏。

这也是通过在字段上使用中间件/2宏来实现的。这就是为什么我们还需要添加

代码语言:javascript
复制
  middleware Absinthe.Middleware.MapGet, :email

在战场上的中间人名单上。

最后,当我们执行查询时

代码语言:javascript
复制
query {
  user(id: 1){
    username
    email
    id
  }
}

我们得到了填充开放字段和被保护字段无效的响应。

代码语言:javascript
复制
{
  "errors": [
    {
      "message": "In field \"email\": unauthenticated",
      "locations": [
        {
          "line": 4,
          "column": 0
        }
      ]
    }
  ],
  "data": {
    "user": {
      "username": "MyAwesomeUsername",
      "id": "1",
      "email": null
    }
  }
}

您还可以使用中间件/3回调,这样您的对象就不会变得过于冗长

代码语言:javascript
复制
  def middleware(middleware, %{identifier: :email} = field, _object) do
    [MySite.Middleware.RequireAuthenticated] ++
      [{Absinthe.Middleware.MapGet, :email}] ++
      middleware
  end

通过创造性地使用__ use _1回调,您可以从主模式文件中获得一堆这样的函数。

票数 9
EN

Stack Overflow用户

发布于 2019-03-20 14:55:09

@voger给出了一个很棒的答案,我只是想根据接受的问题发布一个宏样本。我目前正在使用它来验证架构中的每个字段。

下面是一个宏定义:

代码语言:javascript
复制
defmodule MyApp.Notation do
  defmacro protected_field(field, type, viewers, opts \\ []) do
    {ast, other_opts} =
      case Keyword.split(opts, [:do]) do
        {[do: ast], other_opts} ->
          {ast, other_opts}

        {_, other_opts} ->
          {[], other_opts}
      end

    auth_middleware =
      if viewers !== :public do
        quote do
          middleware(MyApp.Middleware.ProtectedField, unquote(viewers))
        end
      end

    quote do
      field(unquote(field), unquote(type), unquote(other_opts)) do
        unquote(auth_middleware)
        middleware(Absinthe.Middleware.MapGet, unquote(field))
        unquote(ast)
      end
    end
  end
end

然后在您的类型定义中,您可以这样做。

代码语言:javascript
复制
import MyApp.Notation

# ...

object :an_object do
  protected_field(:description, :string, [User, Admin]) do
    middleware(OtherMiddleware)
    resolve(fn _, _, _ ->
      # Custom Resolve
    end)
  end

  protected_field(:name, :stirng, :public, resolve: &custom_resolve/2)
end

解释:

它添加了一个我称之为viewers的参数,我将其转发到中间件,以检查用户类型是否正确。在这个场景中,我实际上有不同的模型,我称之为AdminUser,我可以对照这些模型来检查当前用户。这只是一种方法的例子,所以您的解决方案可能有所不同。对于:public字段,我有一个特例,它只是一个过路。

这很好,因为我可以向中间件注入额外的参数,并将其他所有内容转发到原始的field定义中。

我希望这有助于增加答案。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45236033

复制
相关文章

相似问题

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