授权和身份验证 - Amazon AppSync
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

授权和身份验证

本节介绍用于配置应用程序的安全性和数据保护的选项。

您可以通过五种方式授权应用程序与Amazon AppSyncGraphQL API。您通过在 Amazon AppSync API 或 CLI 调用中指定以下授权类型值之一,以指定您使用哪种授权类型:

  • API_KEY

    适用于使用 API 密钥。

  • AWS_LAMBDA

    为了使用Amazon Lambdafunction.

  • AWS_IAM

    用于使用Amazon Identity and Access Management(IAM) 权限。

  • OPENID_CONNECT

    适用于使用 OpenID Connect 提供商。

  • AMAZON_COGNITO_USER_POOLS

    用于使用 Amazon Cognito 用户池。

这些基本授权类型适用于大多数开发人员。对于更高级的使用案例,您可以通过控制台、CLI 和Amazon CloudFormation. 对于其他授权模式,Amazon AppSync 提供采用上面列出的值(即API_KEYAWS_LAMBDAAWS_IAMOPENID_CONNECT, 和AMAZON_COGNITO_USER_POOLS)。

当你指定API_KEYAWS_LAMBDA,或者AWS_IAM作为主要或默认授权类型,您不能再将其指定为其他授权模式之一。同样,您不能复制API_KEYAWS_LAMBDA要么AWS_IAM在其他授权模式中。您可以使用多个 Amazon Cognito 用户池和 OpenID Connect 提供商。但是,您不能在默认授权模式和任何其他授权模式之间使用重复的 Amazon Cognito 用户池或 OpenID Connect 提供商。您可以使用相应的配置正则表达式为 Amazon Cognito 用户池或 OpenID Connect 提供商指定不同的客户端。

API_KEY 授权

未经身份验证的 API 比经过身份验证的 API 需要更严格的限制。一种对未经身份验证的 GraphQL 终端节点的限制进行控制的方法是使用 API 密钥。API 密钥是应用程序中的一个硬编码值,当您创建未经身份验证的 GraphQL 终端节点时由 Amazon AppSync 服务生成。您可以通过控制台、CLI 或Amazon AppSyncAPI 参考.

API 密钥可配置为最多 365 天,并且您可以将现有到期日期再延长多达 365 天(从到期日期当天开始)。建议将 API 密钥用于开发目的或可以安全公开公有 API 的使用案例。

在客户端,通过标头 x-api-key 指定 API 密钥。

例如,如果您的 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 授权

您可以使用Amazon Lambdafunction. 您可以将 Lambda 函数用于主授权方或次要授权方,但每个 API 可能只有一个 Lambda 授权函数。使用 Lambda 函数进行授权时,以下内容适用:

  • 如果 API 具有AWS_LAMBDAAWS_IAM启用授权模式,则 SiGv4 签名不能用作AWS_LAMBDA授权令牌。

  • 如果 API 具有AWS_LAMBDAOPENID_CONNECT授权模式或AMAZON_COGNITO_USER_POOLS启用授权模式,则 OIDC 令牌不能用作AWS_LAMBDA授权令牌。

  • Lambda 函数为解析器返回的上下文数据不得超过 5MB。

例如,如果您的授权令牌是'ABC123',您可以通过卷曲发送 GraphQL 查询,如下所示:

$ curl -XPOST -H "Content-Type:application/graphql" -H "Authorization:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql

Lambda 函数在每次查询或变更之前被调用,但它们的返回值会被缓存:重复的请求只会在根据 API ID 和身份验证令牌缓存函数之前调用该函数一次。默认情况下,此缓存时间为 300 秒(5 分钟),但可以在 API 级别或通过设置ttlOverride函数返回值中的值。

如果需要,可以指定在调用函数之前验证授权令牌的正则表达式。这些正则表达式用于在调用函数之前验证授权令牌的格式是否正确。任何使用与此正则表达式不匹配的令牌的请求都将被自动拒绝。

用于授权的 Lambda 函数需要一个委托人策略appsync.amazonaws.com应用于它们以允许Amazon AppSync给他们打电话。此操作将在Amazon AppSync控制台;Amazon AppSync控制台可以移除该策略。有关将策略附加到 Lambda 函数的更多信息,请参阅基于资源的策略中的Amazon 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": {} } }

授权函数必须至少返回isAuthorized,一个布尔值,指示请求是否获得授权。Amazon AppSync识别从 Lambda 授权函数返回的以下密钥:

isAuthorized(布尔值,必需)

一个布尔值,指示该值是否在authorizationToken已授权调用 GraphQL API。

如果此值为 true,则继续执行 GraphQL API。如果此值为 false,则为UnauthorizedExceptionRAISE

deniedFields(字符串列表,可选)

其列表被强制更改为null,即使解析器返回了一个值。

每个项目都是一个完全合格的字段 ARN,其形式为arn:aws:appsync:us-east-1:111122223333:apis/GraphQLApiId/types/TypeName/fields/FieldName或者简写形式的TypeName.FieldName. 当两个 API 共享 lambda 函数授权方,并且两个 API 之间的常见类型和字段之间可能存在歧义时,应使用完整的 ARN 表单。

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 的值(如果已配置)或默认值 300 秒(5 分钟)。如果该值为 0,则不会缓存响应。

Lambda 授权方的超时时间为 10 秒。我们建议将函数设计为在尽可能短的时间内执行,以扩展 API 的性能。

多个Amazon AppSyncAPI 可以共享单个身份验证 Lambda 函数。不允许跨账户授权方使用。

在多个 API 之间共享授权函数时,请注意短格式字段名称 (typename.fieldname) 可能会无意中隐藏字段。在中消除字段的歧义deniedFields,则可以以下列形式指定明确的字段 ARNarn:aws:appsync:region:accountId:apis/GraphQLApiId/types/typeName/fields/fieldName.

在中添加 Lambda 函数作为默认授权模式Amazon AppSync:

Console
  1. 登录Amazon AppSync控制台并导航到要更新的 API。

  2. 导航到您的 API 的 Settings (设置) 页面。

    将 API 级别的授权更改为Amazon Lambda.

  3. 选择Amazon Web Services 区域和 Lambda ARN 来授权 API 调用。

    注意

    相应的委托人策略将自动添加,允许Amazon AppSync以调用 Lambda 函数。

  4. (可选)设置响应 TTL 和令牌验证正则表达式。

Amazon CLI
  1. 将以下策略附加到正在使用的 Lambda 函数:

    aws lambda add-permission --function-name "my-function" --statement-id "appsync" --principal appsync.amazonaws.com --action lambda:InvokeFunction --output text
    重要

    如果您希望将函数的策略锁定到单个 GraphQL API 中,则可以运行以下命令:

    aws lambda add-permission --function-name “my-function” --statement-id “appsync” --principal appsync.amazonaws.com --action lambda:InvokeFunction --source-arn “<my AppSync API ARN>” --output text
  2. 更新您的Amazon AppSync使用给定的 Lambda 函数 ARN 作为授权方的 API:

    aws appsync update-graphql-api --api-id example2f0ur2oid7acexample --name exampleAPI --authentication-type AWS_LAMBDA --lambda-authorizer-config authorizerUri="arn:aws:lambda:us-east-2:111122223333:function:my-function"
    注意

    您还可以包括其他配置选项,例如令牌正则表达式。

以下示例介绍了一个 Lambda 函数,该函数演示了 Lambda 函数在用作Amazon 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 授权令牌的问题。

如果你想使用 SiGv4 签名作为 Lambda 授权令牌AWS_IAMAWS_LAMBDA启用了授权模式Amazon AppSync的 API,请执行以下操作:

  • 要创建新的 Lambda 授权令牌,请在 SiGv4 签名中添加随机后缀和/或前缀。

  • 要检索原始 SiGv4 签名,请通过从 Lambda 授权令牌中删除随机前缀和/或后缀来更新您的 Lambda 函数。然后,使用原始 SiGv4 签名进行身份验证。

如果你想使用 OIDC 令牌作为 Lambda 授权令牌OPENID_CONNECT授权模式或AMAZON_COGNITO_USER_POOLSAWS_LAMBDA启用了授权模式Amazon AppSync的 API,请执行以下操作:

  • 要创建新的 Lambda 授权令牌,请向 OIDC 令牌添加随机后缀和/或前缀。

  • 要检索原始 OIDC 令牌,请通过从 Lambda 授权令牌中删除随机前缀和/或后缀来更新您的 Lambda 函数。然后,使用原始 OIDC 令牌进行身份验证。

AWS_IAM 授权

此授权类型强制执行Amazon签名版本 4 签名流程在 GraphQL API 上。您可以将 Identity and Access Management (IAM) 访问策略与此授权类型关联。您的应用程序可以通过使用访问密钥(由访问密钥 ID 和秘密访问密钥组成)或使用由 Amazon Cognito 联合身份提供的短期有效的临时凭证来利用此关联。

如果您希望有访问权限的角色执行所有数据操作:

{ "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 操作的访问,您可以对根 QueryMutationSubscription 字段执行此操作。

{ "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 Connect (OIDC) 令牌。您的应用程序可以利用由 OIDC 提供商定义的用户和权限来控制访问。

发布者 URL 是由您提供给 Amazon AppSync 的唯一需要的配置值,例如 https://auth.example.com。此 URL 必须可通过 HTTPS 寻址。Amazon AppSync 添附/.well-known/openid-configuration到发布者 URL,并在 OpenID 配置中查找 OpenID 配置https://auth.example.com/.well-known/openid-configuration/OpenID Connect 发现规范。它预期会在此 URL 处检索 RFC5785 兼容的 JSON 文档。此 JSON 文档必须包含一个 jwks_uri 密钥,该密钥通过签名密钥指向 JSON Web 密钥集 (JWKS) 文档。

Amazon AppSync 要求 JWKS 包含 JSON 字段algkty, 和kid.

Amazon AppSync 支持 RS256、RS384 和 RS512 作为签名算法。提供商颁发的令牌必须包括颁发令牌的时间 (iat),并可能包含对其进行身份验证的时间 (auth_time)。您可以在 OpenID Connect 配置中为颁发时间 (iatTTL) 和身份验证时间 (authTTL) 提供 TTL 值以进行额外的验证。如果您的提供商授权多个应用程序,还可以提供一个用于按客户端 ID 进行授权的正则表达式 (clientId)。

要验证多个客户端 ID,请使用管道运算符 (“|”),它是正则表达式中的 “或”。例如,如果您的 OIDC 应用程序有四个客户端分别具有客户端 ID 0A1S2D、1F4G9H、1J6L4B、6GS5MG,要仅对前三个客户端 ID 进行验证,则可以在客户端 ID 字段中放置 1F4G9H|1J6L4B|6GS5MG。

AMAZON_COGNITO_USER_POOLS 授权

此授权类型强制实施 Amazon Cognito 用户池提供的 OIDC 令牌。您的应用程序可以利用用户池中的用户和组,并将用户和组与 GraphQL 字段关联以控制访问。

当使用 Amazon Cognito 用户池时,您可以创建用户所属的组。此信息将编码到 JWT 令牌中,当应用程序发送 GraphQL 操作时,会在授权标头中将此令牌发送给 Amazon 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"]) } ...

请注意,您可以省略@aws_auth指令,如果你想默认为一个特定的 grant-or-deny 访问策略。您可以指定 grant-or-deny 当您通过控制台或以下 CLI 命令创建 GraphQL API 时,用户池配置中的策略:

$ 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"}'

使用其他授权模式

添加其他授权模式时,可以直接在 Amazon 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 是 Amazon AppSync GraphQL API 上的默认授权类型。这意味着使用 AWS_IAM 保护没有指令的字段。例如,Query 类型上的 getPost 字段就是这种情况。架构指令使您可以使用多种授权模式。例如,您可以在 Amazon AppSync GraphQL API 上将 API_KEY 配置为其他授权模式,并且可以使用 @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 解析程序映射模板对数据设置访问控制。

在进一步操作之前,如果您不熟悉 Amazon AppSync 中的映射模板,可能希望查看解析程序映射模板参考DynamoDB 解析程序映射模板参考

在以下使用 DynamoDB 的示例中,假设您使用上述的博客文章架构,并仅允许创建文章的用户对其进行编辑。评估过程将是用户在应用程序中获得凭证(例如,使用 Amazon Cognito 用户池),然后将这些凭证作为 GraphQL 操作的一部分进行传递。然后,映射模板将替换条件语句中凭证(如用户名)的值,该值随后将与数据库中的值进行比较。

要添加此功能,请添加 GraphQL 字段 editPost,如下所示:

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 的解析程序映射模板(本节末尾的示例中所示)需要针对您的数据存储执行逻辑检查,以仅允许创建文章的用户对文章进行编辑。由于这是一个编辑操作,因此它与一个UpdateItem在 DynamoDB 中。您可以先执行条件检查,然后再执行此操作,同时使用传递的上下文进行用户身份验证。这些信息存储在一个 Identity 对象中,该对象具有以下值:

{ "accountId" : "12321434323", "cognitoIdentityPoolId" : "", "cognitoIdentityId" : "", "sourceIP" : "", "caller" : "ThisistheprincipalARN", "username" : "username", "userArn" : "Sameasabove" }

在 DynamoDB 中使用此对象UpdateItem调用,则您需要在表中存储用户身份信息以进行比较。首先,您的 addPost 更改需要存储创建者。其次,您的 editPost 更改需要先执行条件检查,然后才能更新。

下面是 addPost 的请求映射模板的一个示例,此模板将用户身份存储为 Author 列:

{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "postId" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "attributeValues" : { "Author" : $util.dynamodb.toDynamoDBJson($context.identity.username) #foreach( $entry in $context.arguments.entrySet() ) #if( $entry.key != "id" ) ,"${entry.key}" : $util.dynamodb.toDynamoDBJson($entry.value) #end #end }, "condition" : { "expression" : "attribute_not_exists(postId)" } }

请注意,Author 属性通过 Identity 对象填充,该对象来自应用程序。

最后,此处的示例介绍了 editPost 的请求映射模板,此模块仅当请求来自创建文章的用户时,才更新博客文章的内容。

{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id": $util.dynamodb.toDynamoDBJson($ctx.args.id), }, "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args), "condition" : { "expression" : "contains(#author,:expectedOwner)", "expressionNames" : { "#author" : "Author" }, "expressionValues" : { ":expectedOwner" : $util.dynamodb.toDynamoDBJson($context.identity.username) } } }

此示例使用 PutItem 覆盖所有值而不是使用 UpdateItem,否则在示例中会更加冗长,但同样的概念适用于 condition 语句块。

筛选信息

有时,在成功写入或读取数据源时,您可能无法控制来自数据源的响应,但又不想向客户端发送不必要的信息。在这些情况下,您可以使用响应映射模板筛选信息。

例如,假设您对博客文章 DynamoDB 表没有适当的索引(如对于的索引)Author)。您可以使用以下映射模板运行 GetItem 查询:

{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "postId" : $util.dynamodb.toDynamoDBJson($ctx.args.id) } }

这将返回所有的值响应,即使调用方不是创建文章的作者。为了防止发生此类情况,在这种情形下您可以对响应映射模板执行访问检查,如下所示:

{ #if($context.result["Author"] == "$context.identity.username") $utils.toJson($context.result); #end }

如果调用方与此检查不匹配,则只返回 Null 响应。

数据源访问

Amazon AppSync 使用 Identity and Access Management (IAM) 角色和访问策略。如果您使用的是现有角色,则需要添加信任策略以便 Amazon AppSync 代入该角色。该信任关系将类似于下面内容:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "appsync.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }

需要将角色的访问策略缩小为仅具有对必要的最少资源集进行操作的权限,这一点非常重要。使用 AppSync 控制台创建数据源并创建角色,则此操作将自动为您完成。但是,当使用 IAM 控制台中的内置示例模板在 Amazon AppSync 控制台之外创建角色时,权限不会自动限定在某个资源上,您应该在将应用程序转移到生产之前执行此操作。