在 JSONB 权限过滤器上使用 X-Hasura-User-Id

Using X-Hasura-User-Id on a JSONB Permission filter

我正在现有的 Postgres 数据库之上设置一个 Hasura 服务器。 schema大量使用JSONB,所有实体建模如下:

EntityName
-----------
id: String
resource: JSONB

在我当前的案例中,我有实体 Appointment。我想创建一个权限,一个用户只能 select 访问作为参与者的约会。

Appointment.resource 是这样建模的:

{
  // ... some other fields ...
  "participant": [
    {
      "actor": {
        "reference": "a826ade6bcbf" // this is X-Hasura-User-Id
      },
    }
  ]
}

这让我想到了以下 "Row select permissions"(将其写在 Web 控制台上,如果它有所不同):

{
  "resource": {
    "_contains": {
      "participant": [
        {
          "actor": { 
            "reference": "X-Hasura-User-Id" 
          }
        }
      ]
    }
  }
}

table 的导出元数据如下所示:

{
  "version": 2,
  "tables": [
    {
      "table": {
        "schema": "public",
        "name": "appointment"
      },
      "select_permissions": [
        {
          "role": "patient",
          "permission": {
            "columns": [
              "id",
              "resource",
            ],
            "filter": {
              "resource": {
                "_contains": {
                  "participant": [
                    {
                      "actor": {
                        "reference": "X-Hasura-User-Id",
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      ]
    },
  ],
}

事实是,如果我使用正确的 headers 在 GraphiQL 上尝试上述规则,我得到一个空响应。但是,如果我将规则更改为 "reference": "a826ade6bcbf"(一个字符串文字),我会得到预期的响应(只有与过滤器匹配的约会)。

似乎 X-Hasura-User-Id 没有被替换为权限。

我做错了什么吗?是否支持此功能?

还有其他授权方式吗?更改当前数据库架构不是可行的解决方案。

从 1.2.1 开始,认为不可能。

查询:

query MyQuery {
  test {
    id
    test_jsonb
    test_text
  }
}

w/ x-hasura-user-id:"a826ade6bcbf",和x-hasura-role:headers中的"user",以及下面的"row select permissions"(点击X-Hasura-User-Id 来自控制台 UI):

{"test_text":{"_eq":"X-Hasura-User-Id"}}

我们得到以下日志:

2020-05-19T21:35:12.879476+00:00 app[web.1]: {"type":"query-log","timestamp":"2020-05-19T21:35:12.877+0000","level":"info","detail":{"request_id":"c1d865c0-be91-4295-b8a0-92ddf5702d70","generated_sql":{"test":{"prepared_arguments":["{\"x-hasura-role\":\"user\",\"x-hasura-user-id\":\"a826ade6bcbf\"}"],"query":"SELECT  coalesce(json_agg(\"root\" ), '[]' ) AS \"root\" FROM  (SELECT  row_to_json((SELECT  \"_1_e\"  FROM  (SELECT  \"_0_root.base\".\"id\" AS \"id\", \"_0_root.base\".\"test_jsonb\" AS \"test_jsonb\", \"_0_root.base\".\"test_text\" AS \"test_text\"       ) AS \"_1_e\"      ) ) AS \"root\" FROM  (SELECT  *  FROM \"public\".\"test\"  WHERE (((\"public\".\"test\".\"test_text\") = (((->>'x-hasura-user-id'))::text)) OR (((\"public\".\"test\".\"test_text\") IS NULL) AND ((((->>'x-hasura-user-id'))::text) IS NULL)))     ) AS \"_0_root.base\"      ) AS \"_2_root\"      "}},"query":{"operationName":"MyQuery","query":"query MyQuery {\n  test {\n    id\n    test_jsonb\n    test_text\n  }\n}\n\nquery MyQuery2 {\n  test(where: {test_jsonb: {_contains: {participant: [{actor: {reference: \"a826ade6bcbf\"}}]}}}) {\n    id\n    test_jsonb\n  }\n}\n"}}}

和预期结果(test table 中还有其他行没有正确的 test_text 值:

{
  "data": {
    "test": [
      {
        "id": 4,
        "test_jsonb": {
          "participant": [
            {
              "actor": {
                "reference": "a826ade6bcbf"
              }
            }
          ]
        },
        "test_text": "a826ade6bcbf"
      }
    ]
  }
}

注意 "prepared_arguments" 及其在查询中的使用方式:->>'x-hasura-user-id'))::text

当我们对下一行 select 权限执行相同操作时(使用基于 JSONB 的权限):

{"test_jsonb":{"_contains":"{participant:[ { actor: {reference: X-Hasura-User-Id }}]}"}}
2020-05-19T21:36:45.580889+00:00 app[web.1]: {"type":"query-log","timestamp":"2020-05-19T21:36:45.580+0000","level":"info","detail":{"request_id":"7dc56852-7501-48fe-8205-3d75a7964c58","generated_sql":{"test":{"prepared_arguments":["{\"x-hasura-role\":\"user\",\"x-hasura-user-id\":\"a826ade6bcbf\"}"],"query":"SELECT  coalesce(json_agg(\"root\" ), '[]' ) AS \"root\" FROM  (SELECT  row_to_json((SELECT  \"_1_e\"  FROM  (SELECT  \"_0_root.base\".\"id\" AS \"id\", \"_0_root.base\".\"test_jsonb\" AS \"test_jsonb\"       ) AS \"_1_e\"      ) ) AS \"root\" FROM  (SELECT  *  FROM \"public\".\"test\"  WHERE ((\"public\".\"test\".\"test_jsonb\") @> (('\"{participant:[ { actor: {reference: X-Hasura-User-Id }}]}\"')::jsonb))     ) AS \"_0_root.base\"      ) AS \"_2_root\"      "}},"query":{"operationName":"MyQuery","query":"query MyQuery {\n  test {\n    id\n    test_jsonb\n    \n  }\n}\n\nquery MyQuery2 {\n  test(where: {test_jsonb: {_contains: {participant: [{actor: {reference: \"a826ade6bcbf\"}}]}}}) {\n    id\n    test_jsonb\n  }\n}\n"}}}

未正确使用准备好的参数(如上)- ((\"public\".\"test\".\"test_jsonb\") @> (('\"{participant:[ { actor: {reference: X-Hasura-User-Id }}]}\"')::jsonb))

如果 X-Hasura-User-Id 以任何方式格式化都没有关系。将在此处作为功能请求提交 - https://github.com/hasura/graphql-engine.

此处的解决方法是将此值提取到列中并通过视图或 computed/generated 列进行查询。