客户端ID强制执行
需要客户端详细信息和工作名称以帮助监控架构使用情况
作为GraphOS Studio指标报告的一部分,服务器可以用请求客户端的名称和版本标记报告的操作。这有助于graph维护者了解哪些客户端正在使用架构中的哪些字段。
客户端还可以(并且应该)为其GraphQL操作命名,这提供了更多关于数据和数据使用方式的信息。
这些信息片段共同帮助团队监控其graph并在安全的情况下对其进行更改。我们强烈建议您的GraphQL网关要求所有请求客户端的详细信息和操作名称。
在GraphOS Router中强制执行
默认情况下,如果客户端在其请求中设置GraphOS Router的apollographql-client-name和apollographql-client-id,apollographql-client-name
和apollographql-client-id
,则支持客户端意识。这些值可以使用路由器配置文件直接覆盖。
也可通过在每个入站请求上使用Rhai脚本强制执行客户端头。
fn supergraph_service(service) {const request_callback = Fn("process_request");service.map_request(request_callback);}fn process_request(request) {log_info("processing request");let valid_clients = ["1", "2"];let valid_client_names = ["apollo-client"];if ("apollographql-client-version" in request.headers && "apollographql-client-name" in request.headers) {let client_header = request.headers["apollographql-client-version"];let name_header = request.headers["apollographql-client-name"];if !valid_clients.contains(client_header) {log_error("Invalid client ID provided");throw #{status: 401,message: "Invalid client ID provided"};}if !valid_client_names.contains(name_header) {log_error("Invalid client name provided");throw #{status: 401,message: "Invalid client name provided"};}}else {log_error("No client headers set");throw #{status: 401,message: "No client headers set"};}}
在Apollo服务器中实施
如果您使用Apollo Server作为您的网关,您可以用自定义插件在每一个入站请求中要求客户端元数据:
💡 提示
下面使用的头名称是Apollo Client默认发送的头名称,但您可以将其更改为客户端使用的任何名称。此外,这些更改必须在使用报告插件中反映出来,以向GraphOS报告客户端头。例如,请参阅使用自定义客户端ID头。
function clientEnforcementPlugin(): ApolloServerPlugin<BaseContext> {return {async requestDidStart() {return {async didResolveOperation(requestContext) {const clientName = requestContext.request.http.headers.get('apollographql-client-name');const clientVersion = requestContext.request.http.headers.get('apollographql-client-version');if (!clientName) {const logString = `Execution Denied: Operation has no identified client`;requestContext.logger.debug(logString);throw new GraphQLError(logString);}if (!clientVersion) {const logString = `Execution Denied: Client ${clientName} has no identified version`;requestContext.logger.debug(logString);throw new GraphQLError(logString);}if (!requestContext.operationName) {const logString = `Unnamed Operation: ${requestContext.queryHash}. All operations must be named`;requestContext.logger.debug(logString);throw new GraphQLError(logString);}},};},};}const server = new ApolloServer({typeDefs,resolvers,plugins: [clientEnforcementPlugin()],});
function clientEnforcementPlugin() {return {async requestDidStart() {return {async didResolveOperation(requestContext) {const clientName = requestContext.request.http.headers.get('apollographql-client-name');const clientVersion = requestContext.request.http.headers.get('apollographql-client-version');if (!clientName) {const logString = `Execution Denied: Operation has no identified client`;requestContext.logger.debug(logString);throw new GraphQLError(logString);}if (!clientVersion) {const logString = `Execution Denied: Client ${clientName} has no identified version`;requestContext.logger.debug(logString);throw new GraphQLError(logString);}if (!requestContext.operationName) {const logString = `Unnamed Operation: ${requestContext.queryHash}. All operations must be named`;requestContext.logger.debug(logString);throw new GraphQLError(logString);}},};},};}const server = new ApolloServer({typeDefs,resolvers,plugins: [clientEnforcementPlugin()],});
为现有客户端添加执行权限
如果客户端已经在使用您的 graph,并且没有提供客户端元数据,添加通用执行权限将打破这些客户端。为了解决这个问题,您应采取以下步骤:
使用其他头
如果您在HTTP请求中还有其他现有的头,可以解析以提取一些客户端信息,您可以从那里提取信息。
GraphOS 路由器
应使用 路由器配置文件来覆盖使用客户端感知头。
Apollo 服务器
如果您改变了标识头,也请更新 使用报告插件以使用新头,这样正确的客户端信息也会发送到工作室。
要求客户端更新其请求
长期的解决方案将需要客户端开始发送提取信息所需的必要头。当客户端正在处理更新请求时,您可以在网关中添加插件代码,但而不是抛出错误,您可以记录一个警告,以便网关团队可以跟踪何时所有请求都已更新。