问题
I'm trying to figure out how can you protect at field level a one-to-many @connection
with @auth
against mutations that shouldn't be allowed. (ie: deny a specific user to run a mutation that will end-up inserting posts as another user.)
Starting with the example for protecting a mutation at the field level: https://aws-amplify.github.io/docs/cli/graphql#field-level-authorization
I tried doing something like this:
type User @model @auth(rules: [{ allow: owner, ownerField: "id" }]) {
id: ID!
posts: [Post]
@connection(name: "UserPosts")
@auth(rules: [{ allow: owner, ownerField: "id" }])
}
type Post @model {
title: String!
user: User!
@connection(name: "UserPosts")
@auth(rules: [{ allow: owner, ownerField: "userPostId" }])
}
Then say there already is a user with an id of regular-user-id
Apparently my auth rules don't stop another user, say with id of: malicious-user-id
to run this mutation:
mutation {
createPost(input:{
title:"Oh this is BAD!"
postUserId: "regular-user-id"
}) {
title
}
}
Running a simple query to make sure this really happened:
query {
getUser(id:"regular-user-id"){
posts{
items
{
title
}
}
}
}
=>
{
"data": {
"getUser": {
"posts": {
"items": [
{
"title": "Regular User title"
},
{
"title": "Oh this is BAD!"
},
]
}
}
}
}
I tried various ways to figure this one out and couldn't find any documentation about bi-directional field level authentication. I'm fairly new to AppSync so I think I must be not getting something, but then this is such common use-case scenario that I'm really surprised there isn't more documentation about it.
Some help would be really appreciated.
回答1:
To protect the Mutation.createPost
mutation such that only the owner of the Post as designated via the postUserId
may access it you add an @auth directive to the Post object definition:
type Post @model @auth(rules: [{ allow: owner, ownerField: "postUserId" }]) {
title: String!
# This will use a field 'postUserId' by default.
user: User!
@connection(name: "UserPosts")
}
With this setup, a mutation:
mutation {
createPost(input:{
title:"Oh this is BAD!"
postUserId: "regular-user-id"
}) {
title
}
}
will fail if the logged in user is not "regular-user-id".
This answer may help fill things in as well https://github.com/aws-amplify/amplify-cli/issues/1507#issuecomment-513042021.
回答2:
Should the malicious user be able to update the Post
title? I know this isn't an exact answer to your question since you're focusing on the relation field, but from trying to understand how to do these kind of things myself, I read a few things about introducing some form of 'everyone' group so you can define auth for user's who aren't owners. Then you could put auth on the entire Post
model so only owners can update any field;
type Post
@model
@auth(rules: [
{ allow: owner, ownerField: "userPostId" },
{ allow: groups, groups: ["everyone"], operations: [read] }
]) {
title: String!
user: User!
@connection(name: "UserPosts")
}
I'm super new to amplify (I'm currently evaluating whether to use it for a project I'm starting), so I could be completely wrong here. If you do actually want a semi-open model where just the reference field has auth, I'm not sure how to do that :(
来源:https://stackoverflow.com/questions/56826035/how-to-do-field-level-auth-for-bi-directional-one-to-many-connection-with-apps