【发布时间】:2020-08-17 13:33:34
【问题描述】:
我需要帮助让我的 Firebase Apollo/GraphQL Cloud Function 进行身份验证和接收查询请求。
- 我实现了一个 Apollo/GraphQL 服务器作为云函数 Firebase/Firestore 使用来自this post 的this repository。
- 我将云功能的权限设置为
allAuthenticatedUsers我正在使用 Firebase Phone Authentication 进行身份验证。 - 我使用来自this stackoverflow answer 的代码来帮助构建 身份验证部分未包含在初始存储库中。
当权限设置为 allUsers 时,Apollo/GraphQL 函数可以正常工作(在 Playground 中测试)。在将权限设置为 allAuthenticatedUsers 并尝试发送经过身份验证的查询后,我收到以下错误响应:
Bearer error="invalid_token" error_description="The access token could not be verified"
我相信我在客户端发送的请求,或者对 ApolloServer 的验证和“上下文”的处理方面犯了错误。我已确认初始用户令牌是正确的。我目前的理论是我发送了错误的标头,或者在客户端或服务器级别以某种方式弄乱了语法。
解释我认为适当的请求流程应该是:
- 在客户端生成令牌
- 从客户端发送的以令牌为标头的查询
- ApolloServer 云函数接收请求
- 令牌已通过 Firebase 验证,提供新的已验证标头令牌
- 服务器接受带有新验证标头令牌的查询并返回数据
如果有人能解释如何将经过身份验证的有效客户端查询发送到 Firebase Apollo/GraphQL 云函数,我们将不胜感激。下面的服务器和客户端代码。
Server.js (ApolloServer)
/* Assume proper imports */
/* Initialize Firebase Admin SDK */
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "[db-url]",
});
/* Async verification with user token */
const verify = async (idToken) => {
var newToken = idToken.replace("Bearer ", "");
let header = await admin.auth().verifyIdToken(newToken)
.then(function(decodedToken) {
let uid = decodedToken.uid;
// Not sure if I should be using the .uid from above as the token?
// Also, not sure if returning the below object is acceptable, or
// if this is even the correct header to send to firebase from Apollo
return {
"Authorization": `Bearer ${decodedToken}`
}
}).catch(function(error) {
// Handle error
return null
});
return header
}
/* Server */
function gqlServer() {
const app = express();
const apolloServer = new ApolloServer({
typeDefs: schema,
resolvers,
context: async ({ req, res }) => {
const verified = await verify(req.headers.Authorization)
console.log('log verified', verified)
return {
headers: verified ? verified: '',
req,
res,
}
},
// Enable graphiql gui
introspection: true,
playground: true
});
apolloServer.applyMiddleware({app, path: '/', cors: true});
return app;
}
export default gqlServer;
Client.js (ApolloClient)
使用these instructions构造的客户端查询。
/* Assume appropriate imports */
/* React Native firebase auth */
firebase.auth().onAuthStateChanged(async (user) => {
const userToken = await user.getIdToken();
/* Client creation */
const client = new ApolloClient({
uri: '[Firebase Cloud Function URL]',
headers: {
Authorization: userToken ? `Bearer ${userToken}` : ''
},
cache: new InMemoryCache(),
});
/* Query test */
client.query({
query: gql`
{
hello
}
`
}).then(
(result) => console.log('log query result', result)
).catch(
(error) => console.log('query error', error)
)
})
更新 05/03/20
我可能已经找到了错误的根源。在我确认之前我不会发布答案,但这是更新。看起来allAuthenticatedUsers 是特定于 Google 帐户而不是 Firebase 的角色。请参阅this part of the google docs 和this stackoverflow answer。
我会做一些测试,但解决方案可能是将权限更改为allUsers,这可能仍需要身份验证。如果我可以让它工作,我会更新一个答案。
【问题讨论】:
-
" 授权:
Bearer ${userToken}? userToken : '' " 这行正确吗? -
@gstvg,根据关于客户端的说明中的第 2 步,这是应该发送的标头
Authorization: Bearer ID_TOKEN。所以我认为是的。参考文档 -cloud.google.com/functions/docs/securing/…, -
是的,你的文档是正确的,我的评论的格式也很难识别,但我认为这一行有一个小错字:你正在做一个 ternay 操作,它总是返回userToken 单独,没有“Bearer”部分,不是吗?
-
@gstvg 很好,我确实不小心把它们翻了。不幸的是,在修复操作并再次尝试查询后,结果仍然是相同的错误。我已经更新了上述问题以反映正确的操作。
-
解决方案有更新吗?
标签: react-native firebase-authentication graphql google-cloud-functions apollo-server