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

How do I configure Amplify to to use multiple AppSync endpoints?

我需要在 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 returns 一个承诺,我一直在研究如何在应用程序的这个顶级实例化中解决一个承诺。我还需要在身份验证事件期间更换此配置。

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

这目前是不可能的。在正式支持顶级等待之前,您应该创建两个 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>
    );
}`

随着 AppSync 现在支持每个 API 的多种身份验证类型,事情可能已经发生了变化;但是提供了关于如何 auth/unauth 在同一端点上实现繁荣的答案。没有回答 how-to 多端点问题,这是导致我来到这里的原因,但在 OP 场景中不再需要。

注意:此答案适用于打字稿——我对 React 不是很熟悉,但我认为它的工作方式完全相同...

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

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

先决条件:

  • 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'
    }
  }
};