Firestore云计算功能apollo graphql认证。

问题描述 投票:0回答:1

我需要帮助让我的Firebase ApolloGraphQL云函数认证和接收查询请求。

  • 我在FirebaseFirestore中实现了一个ApolloGraphQL服务器作为云函数,并使用 本库此职位.
  • 我将云功能的权限设置为allAuthenticatedUsers 而我使用的是 Firebase电话认证 来验证。
  • 我使用了来自 这个stackoverflow的答案 来帮助构建初始存储库中未包含的认证部分。

ApolloGraphQL函数可以正常工作。(用操场测试) 当权限设置为 allUsers. 在将权限设置为 allAuthenticatedUsers 并试图发送验证查询,我收到了以下错误响应。

Bearer error="invalid_token" error_description="The access token could not be verified"

我相信我在客户端发送的请求中犯了错误,或者说在ApolloServer的验证和 "上下文 "的处理上犯了错误。我已经确认初始用户令牌是正确的。我目前的理论是,我发送了错误的头,或者在客户端或服务器层面上以某种方式搞乱了语法。

解释一下我认为适当的请求流程应该是什么。

  1. 客户端生成令牌
  2. 客户端发送的查询,以令牌作为头。
  3. ApolloServer云函数接收到请求
  4. Token由Firebase验证,提供新的验证头令牌。
  5. 服务器用新的验证头标记接受查询并返回数据。

如果有谁能解释一下如何向Firebase ApolloGraphQL云函数发送有效的认证客户端查询,将非常感谢帮助。下面是服务器和客户端的代码。

服务器.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)

客户端查询使用 本说明.

/* 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)
    )
})

更新050320

我可能已经找到了错误的来源。在我确认之前,我不会发布答案,但这里是更新。看起来像 allAuthenticatedUsers 是Google账户特有的角色,而不是Firebase。参见 这一部分的谷歌文档这个stackoverflow的答案.

我将做一些测试,但解决方案 是将权限改为 allUsers 这可能仍然需要认证。如果我可以让它工作,我会更新答案。

react-native firebase-authentication graphql google-cloud-functions apollo-server
1个回答
1
投票

我能够让事情工作。工作请求需要进行以下修改。

  1. 将云函数 "invoker "角色改为包括 allUsers 而不是 allAuthenticatedUsers. 这是因为 allUsers 角色使该函数可以用于http请求(你仍然可以通过sdk验证要求认证)。
  2. 调整服务器和客户端的代码,如下图所示。对头字符串结构进行了小幅修改。

服务器.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)
    )
})
© www.soinside.com 2019 - 2024. All rights reserved.