如何在 Firestore Cloud Functions 上使用 Apollo Server GraphQL 在 TypeScript 中处理身份验证
Posted
技术标签:
【中文标题】如何在 Firestore Cloud Functions 上使用 Apollo Server GraphQL 在 TypeScript 中处理身份验证【英文标题】:How to handle authentication in TypeScript with Apollo Server GraphQL on Firestore Cloud Functions 【发布时间】:2021-05-08 03:57:39 【问题描述】:我一直在关注这篇文章,但尝试使用 TypeScript 而不是 javascript: https://medium.com/@piuccio/running-apollo-server-on-firebase-cloud-functions-265849e9f5b8
但是,当未正确提供 Authorization
标头时,我无法获得正确的行为。在下面的代码中,我抛出了一个Error("No token")
。我还尝试返回一个被拒绝的Promise
,但这给了我一个带有 的HTTP 500 错误(一个空的JSON 响应)。
import gql from 'graphql-tag';
import makeExecutableSchema from 'graphql-tools';
import Config from 'apollo-server-cloud-functions';
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
... resolvers, etc go here...
async function getUser(token: string): Promise<admin.auth.DecodedIdToken>
functions.logger.info('token', token);
if (token === undefined || token === '')
throw new Error("No token");
const idToken = token.split('Bearer ')[1];
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
return decodedIdToken;
export const config: Config =
schema: makeExecutableSchema(
typeDefs,
resolvers,
),
// TODO: DISABLE THESE IN PRODUCTION!
introspection: true,
playground: true,
context: (req, context): Promise<admin.auth.DecodedIdToken> =>
// See https://www.apollographql.com/docs/apollo-server/security/authentication/
functions.logger.info('req headers', req.headers);
const token = req.headers.authorization || '';
const user = getUser(token);
// if (!user) throw new AuthenticationError('you must be logged in');
return user;
,
formatError: formatError,
;
对于 API 支持匿名访问的情况,如何从 getUser()
返回有效的 Promise
?
我更喜欢使用 Apollo 服务器 AuthenticationError
(作为我的身份验证检查),但我无法从 getUser()
返回 null
。
【问题讨论】:
【参考方案1】:按照这里的建议:How to reject in async/await syntax?
我可以将Promise
的类型修改为DecodedIdToken | null
并将null
作为有效值返回。如果我 reject
Promise
则抛出异常并带有错误字符串。
async function getUser(token: string): Promise<DecodedIdToken | null>
functions.logger.info('token', token);
if (token === undefined || token === '')
return null;
// return Promise.reject("No token");
const idToken = token.split('Bearer ')[1];
const decodedIdToken = admin.auth().verifyIdToken(idToken);
return decodedIdToken;
export const config: Config =
schema: makeExecutableSchema(
typeDefs,
resolvers,
),
// TODO: DISABLE THESE IN PRODUCTION!
introspection: true,
playground: true,
context: async (req, context): Promise<DecodedIdToken | null> =>
// See https://www.apollographql.com/docs/apollo-server/security/authentication/
functions.logger.info('req headers', req.headers);
const token = req.headers.authorization || '';
try
const user = await getUser(token);
return Promise.resolve(user);
catch (err)
return Promise.resolve(null); // "No token"
// throw new AuthenticationError('you must be logged in');
,
formatError: formatError,
;
因此,根据您是否希望抛出异常,或者您是否想使用自己的异常(例如 FireStore 的 AuthenticationError
),您可以按照自己的方式构建它。
以下是不同的选项:
Promise.resolve(value)
Promise.resolve(null)
Promise.reject("Not valid") -> throws exception Error("Not valid")
throw new AuthenticationError("Not authorized")
...或使用构造函数语法:
return new Promise<DecodedIdToken | null>((resolve, reject) =>
if (valid)
resolve(value);
else
reject("Not valid");
);
【讨论】:
以上是关于如何在 Firestore Cloud Functions 上使用 Apollo Server GraphQL 在 TypeScript 中处理身份验证的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Cloud 函数中读取 Firestore 文档更新之前/之后的值?
如何在 Cloud Firestore 中使用文档 ID 执行集合组查询
Cloud Functions:如何将 Firestore 集合复制到新文档?