如何将 Amplify 配置为使用多个 AppSync 端点?

Posted

技术标签:

【中文标题】如何将 Amplify 配置为使用多个 AppSync 端点?【英文标题】:How do I configure Amplify to to use multiple AppSync endpoints? 【发布时间】:2019-06-13 20:24:02 【问题描述】:

我需要在 React Native 应用程序中支持经过身份验证和未经身份验证的 AppSync 请求。由于 AppSync 仅允许每个 API 使用一种授权类型,因此我设置了两种 API:一种用于经过身份验证的用户(Cognito 用户池),另一种用于来宾(API 密钥)。

我认为要完成这项工作,我需要在同一个应用程序中有两个不同的 AWSAppSyncClient 配置。

  // authenticated user    
  const appSyncAuthenticatedClient = new AWSAppSyncClient(
    url: Config.APPSYNC_AUTHENTICATED_ENDPOINT,
    region: Config.APPSYNC_REGION,
    auth: 
      type: 'AMAZON_COGNITO_USER_POOLS',
      jwtToken: async () =>
        (await Auth.currentSession()).getAccessToken().getJwtToken()
    
  );

  // guest    
  const appSyncUnauthenticatedClient = new AWSAppSyncClient(
    url: Config.APPSYNC_UNAUTHENTICATED_ENDPOINT,
    region: Config.APPSYNC_REGION,
    auth: 
      type: 'API_KEY',
      apiKey: Config.APPSYNC_API_ID
    
  );

然后根据他们是否登录来决定使用哪个

    Auth.currentAuthenticatedUser()
      .then(user => this.appSyncRunningClient = appSyncAuthenticatedClient)
      .catch(err => this.appSyncRunningClient = appSyncUnauthenticatedClient);

    const App = props => 
      return (
        <ApolloProvider client=this.appSyncRunningClient>
          <Rehydrated>
              <RootStack/>
            </Root>
          </Rehydrated>
        </ApolloProvider>
      );
    ;

    export default App;

这失败了,因为currentAuthenticatedUser 返回了一个承诺,我被困在如何在应用程序的***实例化中解决一个承诺。我还需要在身份验证事件期间更换此配置。

我可以通过什么方式在启动和身份验证事件中动态选择和更改ApolloProvider 配置?

【问题讨论】:

您看过这篇由亚马逊人撰写的文章吗?它涵盖了如何做到这一点(这是一个测试版):read.acloud.guru/… @JeffBailey 该链接讨论了多环境功能(开发、阶段、生产)。我希望在同一个应用程序中实现未经身份验证和经过身份验证的访问。我需要知道如何在一个应用程序中提供多个 Apollo 配置文件。这是一个不同的问题。 @Fook 你是不是偶然发现了这个? @AmieWilt 不是 100%。我使用这篇最近的帖子作为指导:github.com/aws-amplify/amplify-js/issues/… 但 AppSync API 确实允许您添加多种授权类型。为什么需要创建 2 个单独的 API? 【参考方案1】:

目前这是不可能的。在正式支持*** await 之前,您应该创建两个 Apollo 客户端,一个用于 API,一个用于 Cognito。

例如:在您的 App.js 中

export default function App(props) 
  const [client, setClient] = useState(null);

  useEffect(() => 
   checkAuth()
  , []);

  function checkAuth() 
    Auth.currentSession().then(session => 
      const token = session.getIdToken();
      const jwtToken = token.getJwtToken();
      if (typeof jwtToken == "string") 
        const authClientConfig = 
          url: awsmobile.aws_appsync_graphqlEndpoint,
          region: awsmobile.aws_appsync_region,
          disableOffline: true,
          auth: 
            type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
            jwtToken: jwtToken
          
        
        const link = ApolloLink.from([createAuthLink(authClientConfig), createSubscriptionHandshakeLink(authClientConfig)]);
        const authClient = new ApolloClient( link, cache: new InMemoryCache( addTypename: false ) );
        setClient(authClient);
       else 
        throw "error";
      
    ).catch(e => 
      console.log(e);
      const config = 
        url: awsmobile.aws_appsync_graphqlEndpoint,
        region: awsmobile.aws_appsync_region,
        disableOffline: true,
        auth: 
          type: AUTH_TYPE.API_KEY,
          apiKey: awsmobile.aws_appsync_apiKey
        
      
      const link = ApolloLink.from([createAuthLink(config), createSubscriptionHandshakeLink(config)]);
      const authClient = new ApolloClient( link, cache: new InMemoryCache( addTypename: false ) );
        setClient(authClient);
    )
  

    if (!client) 
      return "Loading..."
    

    return (
      <ApolloProvider client=client>
          ...
      </ApolloProvider>
    );
`

【讨论】:

【参考方案2】:

由于 AppSync 现在支持每个 API 的多种身份验证类型,事情可能已经发生了变化;但是提供有关如何在同一端点上进行身份验证/取消身份验证以实现繁荣的答案。没有回答如何引导我来到这里的多端点问题,但在 OPs 场景中不再需要。

注意:此答案适用于 typescript - 我对 react 并不太熟悉,但我认为它的工作原理完全相同...

未经身份验证的访问使用 AWS_IAM / 即 CognitoIdentityPool (配置为允许未经身份验证的访问) Authenticated Access 用户 AMAZON_COGNITO_USER_POOLS 身份验证。

在未经身份验证和经过身份验证的 API.graphql() 调用之间切换。您需要测试当前的身份验证状态,并使用它来覆盖 authMode,就像在 API.graphql() 调用的参数中一样。

作为先决条件:

graphql 中的类型必须设置为允许通过 @aws_iam 和 @aws_cognito_user_pools 进行访问(参见下面的示例) AppSync API 必须配置为允许两种身份验证类型(下面的代码假定 API 默认配置为 AWS_IAM,但允许 CognitoUserPools 作为附加身份验证类型)。这可以在控制台或通过 cloudFormation 进行配置。

API 调用示例代码

      let authMode;
      try 
        authMode = (await Auth.currentUserPoolUser()) ? GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS : undefined;
       catch (err)  

      const result = await API.graphql(
        ...graphqlOperation(statement, gqlAPIServiceArguments),
        authMode
      );

示例 grqphql 类型

type Profile @aws_iam @aws_cognito_user_pools 
  username: ID!
  stuff: String!

我的放大配置


  aws_project_region: 'VALUE_HERE',
  aws_appsync_graphqlEndpoint: 'https://VALUE_HERE/graphql',
  aws_appsync_region: 'VALUE_HERE',
  aws_appsync_authenticationType: 'AWS_IAM',
  aws_appsync_apiKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXX', // This field seems to be required, but the value is ignored.
  Auth: 
    identityPoolId: 'VALUE_HERE',
    region: 'VALUE_HERE',
    userPoolId: 'VALUE_HERE',
    userPoolWebClientId: 'VALUE_HERE',
    oauth: 
      domain: 'VALUE_HERE',
      redirectSignIn: 'VALUE_HERE',
      redirectSignOut: 'VALUE_HERE',
      scope: ['email', 'openid', 'profile', 'aws.cognito.signin.user.admin'],
      responseType: 'code'
    
  
;

【讨论】:

更改 API.graphql 中的 authMode 变量对我不起作用。我正在使用 aws_appsync_authenticationType: 'AMAZON_COGNITO_USER_POOLS',并且我想将 API KEY 用于某些 graphql API 调用。你是怎么解决的? "graphql 中的类型必须设置为允许通过@aws_iam@aws_cognito_user_pools 访问(参见下面的示例)" - 我刚遇到这个问题,让我摸不着头脑,所以它是读到这篇文章让人放心,所以我知道我不只是想弄清楚如何让访客和授权用户访问一个端点,谢谢!

以上是关于如何将 Amplify 配置为使用多个 AppSync 端点?的主要内容,如果未能解决你的问题,请参考以下文章

将 Cloudflare 配置为指向 AWS Amplify

Amplify Shader Editor如何整体移动多个节点

如何将 Quasar 2 与 AWS Amplify 结合使用?

Aws Amplify 在一个 GraphQL Api 中使用多个 Cognito 用户池

AuthError - 错误:未正确配置 Amplify

在 AWS Amplify 中更改我的 GraphQL 架构时如何防止丢失生产数据?