本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
設定授權和身分驗證以保護 GraphQL APIs
AWS AppSync 提供下列授權類型來保護 GraphQLAPIs:API金鑰、Lambda、IAM、OpenID Connect 和 Cognito 使用者集區。每個選項都提供不同的安全方法:
-
API 金鑰授權 :控制未驗證 的限流APIs,提供簡單的安全選項。
-
Lambda 授權 :啟用自訂授權邏輯,詳細解釋函數輸入和輸出。
-
IAM 授權 :使用 AWS的簽章第 4 版簽署程序,允許透過IAM政策進行精細存取控制。
-
OpenID Connect 授權 :與 OIDC相容的服務整合,以進行使用者身分驗證。
-
Cognito 使用者集區 :使用 Cognito 的使用者管理功能實作群組型存取控制。
授權類型
您可以透過五種方式授權應用程式與 AWS AppSync GraphQL 互動API。您可以在 或 CLI呼叫中 AWS AppSync API指定下列其中一個授權類型值,以指定您使用的授權類型:
-
-
API_KEY
-
用於 API金鑰。
-
-
-
AWS_LAMBDA
-
用於使用 AWS Lambda 函數。
-
-
-
AWS_IAM
-
使用 AWS Identity and Access Management (IAM
) 許可。
-
-
-
OPENID_CONNECT
-
對於使用您的 OpenID Connect 提供者。
-
-
-
AMAZON_COGNITO_USER_POOLS
-
用於使用 Amazon Cognito 使用者集區。
-
這些基本授權類型適用於大多數的開發人員。對於更進階的使用案例,您可以透過主控台、 CLI和 新增其他授權模式 AWS CloudFormation。對於其他授權模式, AWS AppSync 會提供採用上述值 (即 、、AWS_IAM
、 OPENID_CONNECT
和 ) API_KEY
AWS_LAMBDA
的授權類型AMAZON_COGNITO_USER_POOLS
。
當您將 API_KEY
AWS_LAMBDA
、 或 指定AWS_IAM
為主要或預設授權類型時,您無法再次將它們指定為其他授權模式之一。同樣地,您無法複製 API_KEY
AWS_LAMBDA
或AWS_IAM
在其他授權模式中複製 。您可以使用多個 Amazon Cognito 使用者集區和 OpenID Connect 供應商。不過,您無法在預設授權模式和任何其他授權模式之間使用重複的 Amazon Cognito 使用者集區或 OpenID Connect 供應商。您可以使用對應的組態規則表達式,為 Amazon Cognito 使用者集區或 OpenID Connect 供應商指定不同的用戶端。
API_KEY 授權
未驗證APIs需要比已驗證的 更嚴格的限流APIs。控制未經驗證的 GraphQL 端點限流的方法之一是透過使用API金鑰。API 金鑰是應用程式中的硬式編碼值,當您建立未經驗證的 GraphQL 端點 AWS AppSync 時,服務會產生該值。您可以從主控台、 CLI或AWS AppSync API參考 輪換API金鑰。
API 金鑰最多可設定 365 天,且您可以將現有的過期日期從該天延長最多 365 天。API 建議將金鑰用於開發用途,或在可安全公開公有 的情況下使用案例API。
在用戶端上,API金鑰由標頭 指定x-api-key
。
例如,如果您的 API_KEY
是 'ABC123'
,您可以經由 curl
來傳送 GraphQL 查詢,如下所示:
$ curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
AWS_LAMBDA 授權
您可以使用 AWS Lambda 函數實作自己的API授權邏輯。您可以為主要或次要授權方使用 Lambda 函數,但每個 可能只有一個 Lambda 授權函數API。使用 Lambda 函數進行授權時,適用下列條件:
-
如果 API 已啟用
AWS_LAMBDA
和AWS_IAM
授權模式,則 SigV4 簽章無法用作AWS_LAMBDA
授權權杖。 -
如果 API 已啟用
AWS_LAMBDA
和OPENID_CONNECT
授權模式或AMAZON_COGNITO_USER_POOLS
授權模式,則無法將該權OIDC杖用作AWS_LAMBDA
授權權杖。請注意,OIDC權杖可以是無記名配置。 -
Lambda 函數不得傳回解析程式超過 5MB 的內容資料。
例如,如果您的授權權杖是 'ABC123'
,您可以透過 curl 傳送 GraphQL 查詢,如下所示:
$ curl -XPOST -H "Content-Type:application/graphql" -H "Authorization:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
Lambda 函數會在每個查詢或突變之前呼叫。可根據 API ID 和身分驗證權杖快取傳回值。根據預設,快取不會開啟,但可以在 API層級啟用,也可以在函數的傳回ttlOverride
值中設定 值。
如有需要,可以指定在呼叫函數之前驗證授權權杖的規則運算式。這些規則運算式用於驗證授權權杖在呼叫函數之前格式是否正確。使用不符合此規則表達式的權杖的任何請求都會自動被拒絕。
用於授權的 Lambda 函數需要套用 的主要政策appsync.amazonaws.com
,才能 AWS AppSync 允許 呼叫它們。此動作會在 AWS AppSync 主控台中自動完成; AWS AppSync 主控台不會移除政策。如需將政策連接至 Lambda 函數的詳細資訊,請參閱 AWS Lambda 開發人員指南中的資源型政策。
您指定的 Lambda 函數將會收到具有下列形狀的事件:
{ "authorizationToken": "ExampleAUTHtoken123123123", "requestContext": { "apiId": "aaaaaa123123123example123", "accountId": "111122223333", "requestId": "f4081827-1111-4444-5555-5cf4695f339f", "queryString": "mutation CreateEvent {...}\n\nquery MyQuery {...}\n", "operationName": "MyQuery", "variables": {} } "requestHeaders": {
application request headers
} }
event
物件包含從應用程式用戶端傳送至 的請求中傳送的標頭 AWS AppSync。
授權函數必須至少傳回 isAuthorized
,布林值表示請求是否已授權。 會 AWS AppSync 識別從 Lambda 授權函數傳回的下列金鑰:
注意
WebSocket 連線操作operationName
中 requestContext
的值由 設定為 AWS AppSync "DeepDish:Connect
"。
isAuthorized
(布林值,必要)-
布林值,指示 中的值是否
authorizationToken
獲授權對 GraphQL 進行呼叫API。如果此值為 true,GraphQL 的執行會API繼續。如果此值為 false,
UnauthorizedException
則會提高 。 deniedFields
(字串清單,選用)-
即使從解析器傳回值
null
,這些清單仍會強制變更為 。每個項目都是ARN完整格式的欄位,可以是
arn:aws:appsync:
或 的簡短格式us-east-1
:111122223333
:apis/GraphQLApiId
/types/TypeName
/fields/FieldName
。當兩個APIs共用 Lambda 函數授權方,且兩個 之間的常見類型和欄位之間可能存在不明確之處時,應使用完整ARN表單APIs。TypeName
.FieldName
resolverContext
(JSON 物件,選用)-
物件JSON在解析器範本
$ctx.identity.resolverContext
中可見。例如,如果解析程式傳回下列結構:{ "isAuthorized":true "resolverContext": { "banana":"very yellow", "apple":"very green" } }
解析器範本
ctx.identity.resolverContext.apple
中的 值為 "very green
"。resolverContext
物件僅支援鍵值對。不支援巢狀金鑰。警告
此JSON物件的總大小不得超過 5MB 。
ttlOverride
(整數,選用)-
應該快取回應的秒數。如果未傳回任何值,API則會使用來自 的值。如果這是 0,則不會快取回應。
Lambda 授權方的逾時為 10 秒。我們建議設計函數,以盡可能在最短的時間內執行,以擴展 的效能API。
多個 AWS AppSync APIs 可以共用單一身分驗證 Lambda 函數。不允許使用跨帳戶授權方。
在多個 之間共用授權函數時APIs,請注意短格式欄位名稱 (
) 可能會不小心隱藏欄位。若要取消模糊 中的欄位typename
.fieldname
deniedFields
,您可以ARN以 的形式指定不明確的欄位arn:aws:appsync:
。region
:accountId
:apis/GraphQLApiId
/types/typeName
/fields/fieldName
若要在 中將 Lambda 函數新增為預設授權模式 AWS AppSync:
下列範例說明 Lambda 函數,其示範 Lambda 函數用作 AWS AppSync 授權機制時可具有的各種身分驗證和失敗狀態:
def handler(event, context): # This is the authorization token passed by the client token = event.get('authorizationToken') # If a lambda authorizer throws an exception, it will be treated as unauthorized. if 'Fail' in token: raise Exception('Purposefully thrown exception in Lambda Authorizer.') if 'Authorized' in token and 'ReturnContext' in token: return { 'isAuthorized': True, 'resolverContext': { 'key': 'value' } } # Authorized with no f if 'Authorized' in token: return { 'isAuthorized': True } # Partial authorization if 'Partial' in token: return { 'isAuthorized': True, 'deniedFields':['user.favoriteColor'] } if 'NeverCache' in token: return { 'isAuthorized': True, 'ttlOverride': 0 } if 'Unauthorized' in token: return { 'isAuthorized': False } # if nothing is returned, then the authorization fails. return {}
規避 SigV4 和OIDC權杖授權限制
下列方法可用來避免在特定授權模式啟用時,無法使用 SigV4 簽章或OIDC權杖作為 Lambda 授權權杖的問題。
如果您想要在 AWS_IAM
和 的授權模式啟用 時,使用 SigV4 AWS AppSync簽章做為 Lambda AWS_LAMBDA
授權權杖API,請執行下列動作:
-
若要建立新的 Lambda 授權權杖,請將隨機字尾和/或字首新增至 SigV4 簽章。
-
若要擷取原始 SigV4 簽章,請從 Lambda 授權權杖中移除隨機字首和/或字尾,以更新您的 Lambda 函數。然後,使用原始 SigV4 簽章進行身分驗證。
如果您想要在 OPENID_CONNECT
的授權模式或 AMAZON_COGNITO_USER_POOLS
和 AWS_LAMBDA
授權模式啟用時,使用OIDC權杖做為 Lambda 授權權杖 AWS AppSync API,請執行下列動作:
-
若要建立新的 Lambda 授權權杖,請將隨機字尾和/或字首新增至OIDC權杖。Lambda 授權權杖不應包含 Bearer 配置字首。
-
若要擷取原始OIDC權杖,請從 Lambda 授權權杖中移除隨機字首和/或字尾,以更新您的 Lambda 函數。然後,使用原始OIDC權杖進行身分驗證。
AWS_IAM 授權
此授權類型會強制執行 GraphQL 上的AWS 簽章第 4 版簽署程序API。您可以將 Identity and Access Management (IAM
如果您希望角色擁有執行所有資料操作的存取權限:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "appsync:GraphQL" ], "Resource": [ "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/*" ] } ] }
您可以在 主控台YourGraphQLApiId
的主API清單頁面 AppSync中,直接在 的名稱下找到 API。或者,您可以使用 來擷取它CLI: aws appsync list-graphql-apis
如果您想要僅限制對於特定 GraphQL 操作的存取權限,您可以在根 Query
、Mutation
以及 Subscription
欄位執行此操作。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "appsync:GraphQL" ], "Resource": [ "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-1>", "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-2>", "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Mutation/fields/<Field-1>", "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Subscription/fields/<Field-1>" ] } ] }
例如,假設您有以下結構描述且您想要限制取得所有文章的存取:
schema { query: Query mutation: Mutation } type Query { posts:[Post!]! } type Mutation { addPost(id:ID!, title:String!):Post! }
角色的對應IAM政策 (例如,您可以連接到 Amazon Cognito 身分集區) 如下所示:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "appsync:GraphQL" ], "Resource": [ "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/posts" ] } ] }
OPENID_CONNECT 授權
此授權類型會強制執行 OIDC合規服務提供的 OpenID 連線
發行方URL是您提供給 的唯一必要組態值 AWS AppSync (例如 https://auth.example.com
)。這URL必須透過 HTTPS. AWS AppSync 附加/.well-known/openid-configuration
至發行者,URL並https://auth.example.com/.well-known/openid-configuration
按照 OpenID Connect Discovery 規格在 找到 OpenID jwks_uri
金鑰,該金鑰指向具有簽署金鑰的 JSON Web 金鑰集 (JWKS) 文件。 AWS AppSync 需要 JWKS包含 kty
和 JSON的欄位kid
。
AWS AppSync 支援廣泛的簽署演算法。
簽署演算法 |
---|
RS256 |
RS384 |
RS512 |
PS256 |
PS384 |
PS512 |
HS256 |
HS384 |
HS512 |
ES256 |
ES384 |
ES512 |
我們建議您使用RSA演算法。由提供者發行的字符必須包含字符發行的時間 (iat
),且可包含驗證時的時間 (auth_time
)。您可以在 OpenID Connect 組態中提供已發出時間 (iatTTL
) 和身分驗證時間 (authTTL
) TTL的值,以進行其他驗證。如果您的提供者授權多個應用程式,您也可以提供用於根據用戶端 ID 授權的一般表達式 (clientId
)。當 OpenID Connect 組態中有 clientId
時, 會要求 與權杖中的 aud
或 宣告相符clientId
,以 AWS AppSync 驗證azp
宣告。
若要驗證多個用戶端,IDs請使用管道運算子 (“|”),這是規則運算式中的「或」。例如,如果您OIDC的應用程式有四個用戶端具有用戶端,IDs例如 0A1S2D, 1F4G9H, 1J6L4B、6GS5MG,以僅驗證前三個用戶端 IDs,您會在用戶端 ID 欄位中放置 1F4G9H |1J6L4B|6GS5MG。
AMAZON_COGNITO_USER_POOLS 授權
此授權類型會強制執行 Amazon Cognito 使用者集區提供的OIDC權杖。您的應用程式可以利用來自另一個 AWS 帳戶的使用者集區和使用者集區中的使用者和群組,並將其與 GraphQL 欄位建立關聯,以控制存取。
使用 Amazon Cognito 使用者集區時,您可以建立使用者所屬的群組。此資訊會以權JWT杖進行編碼,您的應用程式會在傳送 GraphQL 操作時,在授權標頭 AWS AppSync 中傳送至 。您可以使用結構描述上的 GraphQL 指令來控制哪些群組可以叫用欄位上的哪些解析程式,進而為您的客戶提供更具控制性的存取權限。
例如,假設您有下列 GraphQL 結構描述:
schema { query: Query mutation: Mutation } type Query { posts:[Post!]! } type Mutation { addPost(id:ID!, title:String!):Post! } ...
如果您在 Amazon Cognito 使用者集區中有兩個群組 - 部落客和讀者 - 而且您想要限制讀者,以便他們無法新增項目,則您的結構描述應該如下所示:
schema { query: Query mutation: Mutation }
type Query { posts:[Post!]! @aws_auth(cognito_groups: ["Bloggers", "Readers"]) } type Mutation { addPost(id:ID!, title:String!):Post! @aws_auth(cognito_groups: ["Bloggers"]) } ...
請注意,如果您想要預設為存取的特定 grant-or-deny策略,可以省略@aws_auth
指令。當您API透過主控台或透過下列CLI命令建立 GraphQL 時,您可以在使用者集區組態中指定 grant-or-deny策略:
$ aws appsync --region us-west-2 create-graphql-api --authentication-type AMAZON_COGNITO_USER_POOLS --name userpoolstest --user-pool-config '{ "userPoolId":"test", "defaultEffect":"ALLOW", "awsRegion":"us-west-2"}'
使用其他授權模式
當您新增其他授權模式時,可以直接在 AWS AppSync GraphQL API層級設定授權設定 (即您可以直接在GraphqlApi
物件上設定authenticationType
的欄位),並在結構描述上充當預設值。這表示任何沒有特定指令的類型都必須通過API層級授權設定。
在結構描述層級上,您可以在結構描述上使用指示詞來指定其他授權模式。您可以在結構描述中的個別欄位上指定授權模式。例如,針對 API_KEY
授權,您可以在結構描述物件類型定義/欄位上使用 @aws_api_key
。結構描述欄位和物件類型定義支援下列指示詞:
-
@aws_api_key
- 指定欄位會經由API_KEY
授權。 -
@aws_iam
- 指定欄位會經由AWS_IAM
授權。 -
@aws_oidc
- 指定欄位會經由OPENID_CONNECT
授權。 -
@aws_cognito_user_pools
- 指定欄位會經由AMAZON_COGNITO_USER_POOLS
授權。 -
@aws_lambda
- 指定欄位會經由AWS_LAMBDA
授權。
您無法將 @aws_auth
指示詞搭配使用其他授權模式。@aws_auth
只能在沒有其他授權模式的 AMAZON_COGNITO_USER_POOLS
授權內容中運作。但是,您可以搭配相同的引數,使用 @aws_cognito_user_pools
指示詞來取代 @aws_auth
指示詞。這兩者的主要差異是您可以在任何欄位和物件類型定義上指定 @aws_cognito_user_pools
。
為了了解其他授權模式如何運作以及如何在結構描述上指定這些模式,讓我們看看以下結構描述:
schema { query: Query mutation: Mutation } type Query { getPost(id: ID): Post getAllPosts(): [Post] @aws_api_key } type Mutation { addPost( id: ID! author: String! title: String! content: String! url: String! ): Post! } type Post @aws_api_key @aws_iam { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! } ...
在此結構描述中,假設 AWS_IAM
是 AWS AppSync GraphQL 上的預設授權類型API。這表示沒有指示詞的欄位會使用 AWS_IAM
進行保護。例如,Query
類型的 getPost
欄位就是這種情況。結構描述指示詞可讓您使用超過一種授權模式。例如,您可以在 AWS AppSync GraphQL 上將 API_KEY
設定為其他授權模式API,並且可以使用@aws_api_key
指令標記欄位 (例如getAllPosts
,在此範例中)。指示詞會在欄位層級運作,因此您也需要將 API_KEY
存取權限提供給 Post
類型。您可以透過在 Post
類型中使用指示詞標記每個欄位,或是使用 @aws_api_key
指示詞標記 Post
類型,來執行此作業。
若要進一步限制對 Post
類型中欄位的存取,您可以針對 Post
類型中的個別欄位使用指示詞,如下所示。
例如,您可以將 restrictedContent
欄位新增到 Post
類型,並使用 @aws_iam
指示詞限制對該項目進行存取。AWS_IAM
已驗證請求可以存取 restrictedContent
,但 API_KEY
請求將無法存取它。
type Post @aws_api_key @aws_iam{ id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! restrictedContent: String! @aws_iam } ...
精細定義存取控制
上述資訊示範了如何限制存取權限,或將存取權限授予特定 GraphQL 欄位。若您希望根據特定條件設定資料的存取控制 (例如根據進行呼叫的使用者,以及使用者是否擁有資料),您可以在解析程式中使用映射範本。您也可以執行更複雜的商業邏輯;我們會在篩選資訊中進行說明。
本節說明如何使用 DynamoDB 解析器映射範本在資料上設定存取控制。
在繼續進一步操作之前,如果您不熟悉 中的映射範本 AWS AppSync,建議您檢閱 Resolver 映射範本參考和 DynamoDB 的 Resolver 映射範本參考。
在下列使用 DynamoDB 的範例中,假設您正在使用上述部落格文章結構描述,而且只有建立文章的使用者才能編輯。評估程序需使用者獲得應用程式的登入資料,例如使用 Amazon Cognito 使用者集區,然後將這些登入資料做為 GraphQL 操作的一部分。映射範本接著將取代在條件式陳述式中的登入資料值 (例如使用者名稱),此資訊接著將與資料庫中的值進行比較。
若要新增此功能,請新增 editPost
的 GraphQL 欄位,如下所示:
schema { query: Query mutation: Mutation } type Query { posts:[Post!]! } type Mutation { editPost(id:ID!, title:String, content:String):Post addPost(id:ID!, title:String!):Post! } ...
editPost
的解析程式映射範本 (顯示於本區段末端的範例中) 需要針對您的資料存放區執行邏輯檢查,只允許建立文章的使用者可對其進行編輯。由於這是編輯操作,因此會對應至 DynamoDB UpdateItem
中的 。 DynamoDB 在執行此動作前可以使用透過使用者身分驗證傳遞的上下文來執行條件檢查。此資訊存放在 Identity
物件中,有以下值:
{ "accountId" : "12321434323", "cognitoIdentityPoolId" : "", "cognitoIdentityId" : "", "sourceIP" : "", "caller" : "ThisistheprincipalARN", "username" : "username", "userArn" : "Sameasabove" }
若要在 DynamoDBUpdateItem
呼叫中使用此物件,您需要將使用者身分資訊存放在 資料表中以供比較。首先,您的 addPost
變動需要儲存建立者。其次,您的 editPost
變動需在更新前執行條件式檢查。
以下是addPost
將使用者身分儲存為Author
資料欄的解析器程式碼範例:
import { util, Context } from '@aws-appsync/utils'; import { put } from '@aws-appsync/utils/dynamodb'; export function request(ctx) { const { id: postId, ...item } = ctx.args; return put({ key: { postId }, item: { ...item, Author: ctx.identity.username }, condition: { postId: { attributeExists: false } }, }); } export const response = (ctx) => ctx.result;
請注意,Author
屬性從來自於應用程式的 Identity
物件發布。
最後,以下是 的解析程式程式碼範例editPost
,只有在請求來自建立文章的使用者時,才會更新部落格文章的內容:
import { util, Context } from '@aws-appsync/utils'; import { put } from '@aws-appsync/utils/dynamodb'; export function request(ctx) { const { id, ...item } = ctx.args; return put({ key: { id }, item, condition: { author: { contains: ctx.identity.username } }, }); } export const response = (ctx) => ctx.result;
此範例使用覆寫所有值的 PutItem
,而不是 UpdateItem
,但相同的概念適用於condition
陳述式區塊。
篩選資訊
在某些情況下,您無法控制資料來源的回應,但又不想在成功寫入或讀取資料來源時,將不必要的資訊傳送給用戶端。如果發生這些情況,您可以使用回應映射範本來篩選資訊。
例如,假設您的部落格文章 DynamoDB 資料表 (例如 上的索引) 上沒有適當的索引Author
。您可以使用下列解析程式:
import { util, Context } from '@aws-appsync/utils'; import { get } from '@aws-appsync/utils/dynamodb'; export function request(ctx) { return get({ key: { ctx.args.id } }); } export function response(ctx) { if (ctx.result.author === ctx.identity.username) { return ctx.result; } return null; }
即使呼叫者不是建立文章的作者,請求處理常式也會擷取項目。為了防止傳回所有資料,回應處理常式會檢查以確保呼叫者符合項目的作者。如果發起人不符合此檢查,只會傳回 nul在某些情況下,您無法控制數據源的響應,但又不想在成功寫入或讀取數據源時將不必要的信息發送給客戶端。l 回應。
資料來源存取
AWS AppSync 使用 Identity and Access Management (IAM
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "appsync.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
縮小角色的存取政策範圍,使其只能對必要的最少資源集合採取行動,是非常重要的。使用 AppSync 主控台建立資料來源和建立角色時,會自動為您完成此操作。不過,使用主控台的內建範例範本IAM在主控台之外 AWS AppSync建立角色時,不會自動縮小資源的許可範圍,而且您應該在將應用程式移至生產環境之前執行此動作。