如何在Lambda函数中以owner权限调用AWS Amplify GraphQL API?
问题描述
Schema定义
type Notification @auth(rules: [{ allow: owner, operations: [create, read, update] }]) @model { content: String! id: ID! }
Lambda相关代码
const createNotificationRequest = new Request( process.env.API_PROJECT_GRAPHQLAPIENDPOINTOUTPUT, { body: JSON.stringify({ query: /* GraphQL */ ` mutation CreateNotification( $input: CreateNotificationInput! $condition: ModelNotificationConditionInput ) { createNotification(input: $input, condition: $condition) { content id createdAt updatedAt owner } } `, variables: { input: { content: "yo", owner: `${sub}::${username}`, }, }, }), headers: { // Authorization: somethingGoesHere, "Content-Type": "application/json", }, method: "POST", } ); const createNotificationRequestResult = await fetch( createNotificationRequest ); console.log(createNotificationRequestResult);
请求返回结果
Response { size: 0, timeout: 0, [Symbol(Body internals)]: { body: PassThrough { _readableState: [ReadableState], _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, _writableState: [WritableState], allowHalfOpen: true, [Symbol(kCapture)]: false, [Symbol(kCallback)]: null }, disturbed: false, error: null }, [Symbol(Response internals)]: { url: 'https://abcdefg.appsync-api.us-east-1.amazonaws.com/graphql', status: 401, statusText: 'Unauthorized', headers: Headers { [Symbol(map)]: [Object: null prototype] }, counter: 0 } }
Lambda函数无法以owner权限创建Notification对象(已获取该owner的sub和username),尝试给Lambda添加IAM权限但未生效,询问能否实现该需求。
解决方案
方式一:IAM授权+AppSync规则修正
这是最适配现有架构的方案,需要两步配置:
给Lambda附加AppSync权限
给Lambda的IAM角色添加如下策略,限定只允许调用目标Mutation:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "appsync:GraphQL", "Resource": "arn:aws:appsync:us-east-1:YOUR_ACCOUNT_ID:apis/YOUR_API_ID/types/Mutation/fields/createNotification" } ] }替换其中的
YOUR_ACCOUNT_ID和YOUR_API_ID为实际值。修改Schema的认证规则
新增一条IAM授权规则,允许Lambda在指定条件下创建数据(确保传入的owner和身份匹配):type Notification @auth(rules: [ { allow: owner, operations: [create, read, update] }, { allow: iam, operations: [create], condition: { eq: ["${ctx.args.input.owner}", "${ctx.identity.username}"] } } ]) @model { content: String! id: ID! }Lambda请求添加IAM签名
使用AWS SDK的签名工具给请求添加授权头,示例代码:import { SignatureV4 } from "@aws-sdk/signature-v4"; import { Sha256 } from "@aws-crypto/sha256-js"; import { defaultProvider } from "@aws-sdk/credential-provider-node"; const signer = new SignatureV4({ credentials: defaultProvider(), region: process.env.AWS_REGION, service: "appsync", sha256: Sha256, }); const request = new Request( process.env.API_PROJECT_GRAPHQLAPIENDPOINTOUTPUT, { body: JSON.stringify({ query: /* GraphQL */ ` mutation CreateNotification($input: CreateNotificationInput!) { createNotification(input: $input) { content id owner } } `, variables: { input: { content: "yo", owner: `${sub}::${username}` } }, }), headers: { "Content-Type": "application/json", host: new URL(process.env.API_PROJECT_GRAPHQLAPIENDPOINTOUTPUT).hostname, }, method: "POST", } ); const signedRequest = await signer.sign(request); const response = await fetch(signedRequest); const data = await response.json();
方式二:模拟用户JWT(Cognito场景)
如果系统用Cognito用户池做认证,可以直接获取目标用户的ID Token,放在请求头中:
headers: { "Authorization": "USER_ID_TOKEN_HERE", "Content-Type": "application/json", },
AppSync会解析令牌中的sub和username,自动匹配owner规则。需要确保Lambda有获取用户令牌的权限(比如调用Cognito的adminInitiateAuth接口)。
方式三:直接操作DynamoDB(更高效)
跳过AppSync的HTTP调用,让Lambda直接操作@model生成的DynamoDB表:
- 给Lambda添加DynamoDB的
PutItem权限 - 使用AWS SDK直接写入数据:
这种方式不需要处理AppSync的认证逻辑,性能更优。import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb"; import { marshall } from "@aws-sdk/util-dynamodb"; const client = new DynamoDBClient({ region: process.env.AWS_REGION }); const command = new PutItemCommand({ TableName: "Notification", Item: marshall({ id: "UUID_GENERATED", content: "yo", owner: `${sub}::${username}`, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }) }); await client.send(command);
内容的提问来源于stack exchange,提问作者John DeBord
相关产品推荐
相关产品推荐

