我正在尝试用较新的@aws-amplify
软件包填充jwtToken,事实证明有些困难。
尝试运行Query
时,会出现以下错误:Uncaught (in promise) No current user
从源头上可以看到,如果我将身份验证类型设置为AMAZON_COGNITO_USER_POOLS
,则必须使用jwt token
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(),
会按照上面的代码所示返回所需的诺言...所以我看不到为什么这会失败?
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
答案 0 :(得分:1)
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端点(AppSync设置中的Additional authorization providers
)的Cognito身份验证之外,还要添加基于api-key的身份验证。在下面的示例中,id
和publicProperty
可以使用已配置的API密钥通过somePublicQuery
进行访问
type Query {
somePublicQuery:[SomeModel!]!
@aws_api_key
}
type SomeModel {
id: ID! @aws_api_key
privateProperty: String!
publicProperty: String! @aws_api_key
}
如果我参考问题中指出的示例,那么这将在客户端发生变化。
headerBasedAuth
可以使用一组标头数组,一个标头用于api键,一个标头用于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
函数中,您将拥有类似这样的东西
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.
}
}
}