Firestore 云功能 apollo graphql 身份验证
Posted
技术标签:
【中文标题】Firestore 云功能 apollo graphql 身份验证【英文标题】:Firestore cloud functions apollo graphql authentication 【发布时间】:2020-08-17 13:33:34 【问题描述】:我需要帮助让我的 Firebase Apollo/GraphQL Cloud Function 进行身份验证和接收查询请求。
我实现了一个 Apollo/GraphQL 服务器作为云函数 Firebase/Firestore 使用来自this post 的this repository。 我将云功能的权限设置为allAuthenticatedUsers
我正在使用 Firebase Phone
Authentication 进行身份验证。
我使用来自this *** 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 *** answer。
我会做一些测试,但解决方案可能是将权限更改为allUsers
,这可能仍需要身份验证。如果我可以让它工作,我会更新一个答案。
【问题讨论】:
" 授权:Bearer $userToken
? userToken : '' " 这行正确吗?
@gstvg,根据关于客户端的说明中的第 2 步,这是应该发送的标头Authorization: Bearer ID_TOKEN
。所以我认为是的。参考文档 -cloud.google.com/functions/docs/securing/…,
是的,你的文档是正确的,我的评论的格式也很难识别,但我认为这一行有一个小错字:你正在做一个 ternay 操作,它总是返回userToken 单独,没有“Bearer”部分,不是吗?
@gstvg 很好,我确实不小心把它们翻了。不幸的是,在修复操作并再次尝试查询后,结果仍然是相同的错误。我已经更新了上述问题以反映正确的操作。
解决方案有更新吗?
【参考方案1】:
我能够让事情正常进行。工作请求需要进行以下更改:
-
更改云函数“调用者”角色以包含
allUsers
而不是 allAuthenticatedUsers
。这是因为allUsers
角色使该功能可用于 http 请求(您仍然可以要求通过 sdk 验证进行身份验证)
调整服务器和客户端的代码,如下所示。对标头字符串构造进行了细微更改。
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) =>
if (idToken)
var newToken = idToken.replace("Bearer ", "");
// var newToken = idToken
let header = await admin.auth().verifyIdToken(newToken)
.then(function(decodedToken)
// ...
return
"Authorization": 'Bearer ' + decodedToken
).catch(function(error)
// Handle error
return null
);
return header
else
throw 'No Access'
/* Server */
function gqlServer()
const app = express();
const apolloServer = new ApolloServer(
typeDefs: schema,
resolvers,
context: async ( req, res ) =>
// headers: req.headers,
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)
/* Assume appropriate imports */
/* React Native firebase auth */
firebase.auth().onAuthStateChanged(async (user) =>
const userToken = await user.getIdToken();
/* Client creation */
const userToken = await user.getIdToken();
const client = new ApolloClient(
uri: '[Firebase Cloud Function URL]',
headers:
"Authorization": userToken ? 'Bearer ' + userToken : ''
,
cache: new InMemoryCache(),
);
client.query(
query: gql`
hello
`
).then(
(result) => console.log('log query result', result)
).catch(
(error) => console.log('query error', error)
)
)
【讨论】:
以上是关于Firestore 云功能 apollo graphql 身份验证的主要内容,如果未能解决你的问题,请参考以下文章