加入我们,于10月8日至10日在纽约市,了解关于GraphQL联邦和API平台工程最新的技巧、趋势和新闻。加入2024年纽约市的GraphQL峰会
文档
免费开始

客户端ID强制执行

需要客户端详细信息和工作名称以帮助监控架构使用情况

服务器可观测性路由器

作为指标报告的一部分,服务器可以用请求客户端的名称和版本标记报告的操作。这有助于维护者了解哪些客户端正在使用架构中的哪些

客户端还可以(并且应该)为其GraphQL操作命名,这提供了更多关于数据和数据使用方式的信息。

这些信息片段共同帮助团队监控其graph并在安全的情况下对其进行更改。我们强烈建议您的网关要求所有请求客户端的详细信息和

在GraphOS Router中强制执行

默认情况下,如果客户端在其请求中设置apollographql-client-nameapollographql-client-idapollographql-client-nameapollographql-client-id,则支持客户端意识。这些值可以使用路由器配置文件直接覆盖。

也可通过在每个入站请求上使用Rhai脚本强制执行客户端头。

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服务器中实施

如果您使用作为您的网关,您可以用自定义插件在每一个入站请求中要求客户端元数据:

💡 提示

下面使用的头名称是默认发送的头名称,但您可以将其更改为客户端使用的任何名称。此外,这些更改必须在使用报告插件中反映出来,以向报告客户端头。例如,请参阅使用自定义客户端ID头

index.ts
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()],
});
index.js
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 服务器

如果您改变了标识头,也请更新 使用报告插件以使用新头,这样正确的客户端信息也会发送到工作室。

要求客户端更新其请求

长期的解决方案将需要客户端开始发送提取信息所需的必要头。当客户端正在处理更新请求时,您可以在网关中添加插件代码,但而不是抛出错误,您可以记录一个警告,以便网关团队可以跟踪何时所有请求都已更新。

下一页
首页
评分文章评分在GitHub上编辑Edit论坛Discord

©2024Apollo Graph Inc.,以Apollo GraphQL的名义。

隐私策略

公司