在 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 列进行查询。
我正在现有的 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 列进行查询。