如何在 apollo-client 中使用 AMAZON_COGNITO_USER_POOLS

3

我试图使用更新的@aws-amplify包填充我的jwtToken,但这证明是有些困难的。

当尝试运行一个Query时,我会收到以下错误:Uncaught(在承诺中)没有当前用户

我可以从源代码中看到,如果将auth类型设置为AMAZON_COGNITO_USER_POOLS,那么就必须使用jwt令牌

        case AUTH_TYPE.AMAZON_COGNITO_USER_POOLS:
        case AUTH_TYPE.OPENID_CONNECT:
            const { jwtToken = '' } = auth;
            promise = headerBasedAuth({ header: 'Authorization', value: jwtToken }, operation, forward);

这导致我尝试生成我的JWT令牌,这就是我的知识的瓶颈。我知道 jwtToken: async() => (await Auth.currentSession()).getIdToken().getJwtToken() 返回一个promise,正如上面的代码中所需的一样... 所以我不明白为什么会失败?

_app.js(next.js)

import Amplify from '@aws-amplify/core'
import { Auth } from '@aws-amplify/auth'
import { ApolloProvider } from '@apollo/react-hooks'
import { ApolloLink } from 'apollo-link'
import { createAuthLink } from 'aws-appsync-auth-link'
import { InMemoryCache, ApolloClient } from '@apollo/client'
import { createHttpLink } from 'apollo-link-http'

import awsExports from '../aws-exports'

Amplify.configure(awsExports)
Auth.configure(awsExports)

const url = awsExports.aws_appsync_graphqlEndpoint
const region = awsExports.aws_appsync_region

const auth = {
  type: awsExports.aws_appsync_authenticationType,
  jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken(),
}
const link = ApolloLink.from([createAuthLink({ url, region, auth }), createHttpLink({ uri: url })])
const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
})

const MyApp = function ({ Component, pageProps, router }) {
  return (
        .....
          <ApolloProvider client={client}>
        .....
  )
}

export default MyApp
1个回答

4
jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken()

这是一个部分正确的实现,当用户已经登录时可以正常工作。
当用户未登录时,Auth.currentSession() 将会报错Uncaught (in promise) No current user
以下代码将演示此错误。
 Amplify.configure(awsExports);

 Auth.signOut()
    .then(_ => auth.jwtToken())
    .then(console.log)
    .catch(console.error);

以下是一个示例,您可以在其中获取令牌(请在代码中替换用户名和密码)。
Amplify.configure(awsExports);

Auth.signIn(<username>, <password>)
    .then(_ => auth.jwtToken())
    .then(console.log)
    .catch(console.error);

这个问题的解决方案是确保在用户登录时请求令牌,或者优雅地处理错误。
更新:
如果有公共查询,则建议为AppSync GraphQL端点添加基于API密钥的身份验证(在AppSync设置中的“附加授权提供程序”中)。 在下面的示例中,可以通过配置的API密钥访问id和publicProperty以及通过somePublicQuery进行访问。
type Query {
  somePublicQuery:[SomeModel!]!
  @aws_api_key
}

type SomeModel {
  id: ID! @aws_api_key
  privateProperty: String!
  publicProperty: String! @aws_api_key
}

如果我参考问题中指出的例子,那么客户端端会发生以下变化。

headerBasedAuth 可以接受一个头部数组,其中一个用于api-key,另一个用于 Cognito 令牌。

const headerBasedAuth = async ( authHeaders: Array<Headers> = [], operation, forward) => {
  const origContext = operation.getContext();
  let headers = {
    ...origContext.headers,
    [USER_AGENT_HEADER]: USER_AGENT,
  };

  for ( let authHeader of authHeaders) { // Handle the array of auth headers
    let { header, value } = authHeader;
    if (header && value) {
      const headerValue = typeof value === 'function' ? await value.call(undefined) : await value;

      headers = {
          ...{ [header]: headerValue },
          ...headers
      };
    }
  }

  operation.setContext({
      ...origContext,
      headers,
  });

  return forward(operation);

};

authLink函数中,不使用switch语句,可以采用如下方式。
const { apiKey = '', jwtToken = '' } = auth;
promise = headerBasedAuth([{ header: 'X-Api-Key', value: apiKey }, { header: 'Authorization', value: jwtToken }], operation, forward);

最后,auth对象的样子应该像这样。
const auth = {
  apiKey: awsExports.aws_appsync_apiKey, //Add apiKey to your aws-exports
  jwtToken: async () => {
      try {
        return (await Auth.currentSession()).getIdToken().getJwtToken()
      } catch (e) {
        console.error(e);
        return ""; // In case you don't get the token, hopefully that is a public api and that should work with the API Key alone.
      }
    }
}

谢谢GSSWain,那么我假设对于公共查询,我需要确保我的角色在模式中更新为“role: public”? - Jamie Hutber
非常感谢你再次帮忙,@GSSWain!我非常感激你深入的解答,并期待明天可以检查一下 :) 如果你有兴趣,我还有另一个关于RDS MySQL数据库和应用程序同步的普遍问题 :D https://stackoverflow.com/questions/64176243/failed-to-start-api-mock-endpoint-error-cloudformation-stack-parameter-rdsregio - Jamie Hutber
这非常有帮助,非常感谢! - mufasa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接