C# gRPC 客户端拦截器设置授权 header
C# gRPC client interceptor set Authorization header
我正在尝试为配置的 API 令牌始终设置的 gRCP 客户端创建一个拦截器。
问题是我找不到设置 context.Options.Headers
的方法。如果我正在阅读文档,我需要调用 WithHeaders
方法并且需要设置新的元数据以便我可以添加更多 headers。唯一的问题是仍然没有创建 headers object.
有人知道我做错了什么吗?
文档:
https://grpc.github.io/grpc/csharp/api/Grpc.Core.CallOptions.html?q=calloptions
代码:
using System;
using Floof.Common.Exceptions.IoC;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Floof.Common.GrpcClient.Interceptors
{
public class AuthorizationHeaderInterceptor : Interceptor
{
private readonly ILogger<AuthorizationHeaderInterceptor> _logger;
public const string Section = "gRPC";
public const string Key = "ApiKey";
private const string AuthorizationHeader = "Authorization";
private readonly string _apiToken;
public AuthorizationHeaderInterceptor(
ILogger<AuthorizationHeaderInterceptor> logger,
IConfiguration configuration
)
{
if (configuration == null)
throw new ArgumentNullException(nameof(configuration));
_logger = logger;
var apiToken = configuration.GetSection(Section)?[Key];
if (string.IsNullOrWhiteSpace(apiToken))
throw new IoCConfigurationException("API key", Section, Key);
_apiToken = apiToken;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation
)
{
// Check if the headers are not null, if so, initialize new headers
if (context.Options.Headers == null)
{
_logger.LogDebug("Adding gRPC option headers");
context.Options.WithHeaders(new Metadata());
}
// gRPC calls and responses can also include metadata that's similar to HTTP headers. This metadata is mostly
// invisible to gRPC itself and is passed through to be processed by your application code or middleware.
// Metadata is represented as key/value pairs, where the key is a string and the value is either a string or
// binary data. You don’t need to specify metadata in the .proto file.
// https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/metadata
var authorization = new Metadata.Entry(AuthorizationHeader, _apiToken);
// Check if the header already has an Authorization header within. For now we agreed on that no one is allowed
// to set this header. If we want to use this client for external API services as well, we need to look up if
// this is a good client to use and what changes it takes for this client to pair with another API then the Floof cloud
var setAuthorizationHeaderEntry = context.Options.Headers.Get(AuthorizationHeader);
if (setAuthorizationHeaderEntry != null)
{
_logger.LogWarning("Replacing the Authorization header by the configured Floof API key value.");
// Remove the header out of the options because we set the configured key
context.Options.Headers.Remove(setAuthorizationHeaderEntry);
}
// Add the header to the context.
context.Options.Headers.Add(authorization);
// replace the context with the authorization context
return base.AsyncUnaryCall(request, context, continuation);
}
}
}
在调用 return base.AsyncUnaryCall
时尝试传递新上下文 new ClientInterceptorContext
并设置所有需要的 headers 应该会有所帮助:
public class AuthorizationHeaderInterceptor : Interceptor
{
...
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
...
var headers = new Metadata();
headers.Add(new Metadata.Entry("Authorization", _token));
var newOptions = context.Options.WithHeaders(headers);
var newContext = new ClientInterceptorContext<TRequest, TResponse>(
context.Method,
context.Host,
newOptions);
return base.AsyncUnaryCall(request, newContext, continuation);
}
}
https://github.com/grpc/grpc-dotnet/issues/1255#issuecomment-811635583
我正在尝试为配置的 API 令牌始终设置的 gRCP 客户端创建一个拦截器。
问题是我找不到设置 context.Options.Headers
的方法。如果我正在阅读文档,我需要调用 WithHeaders
方法并且需要设置新的元数据以便我可以添加更多 headers。唯一的问题是仍然没有创建 headers object.
有人知道我做错了什么吗?
文档:
https://grpc.github.io/grpc/csharp/api/Grpc.Core.CallOptions.html?q=calloptions
代码:
using System;
using Floof.Common.Exceptions.IoC;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Floof.Common.GrpcClient.Interceptors
{
public class AuthorizationHeaderInterceptor : Interceptor
{
private readonly ILogger<AuthorizationHeaderInterceptor> _logger;
public const string Section = "gRPC";
public const string Key = "ApiKey";
private const string AuthorizationHeader = "Authorization";
private readonly string _apiToken;
public AuthorizationHeaderInterceptor(
ILogger<AuthorizationHeaderInterceptor> logger,
IConfiguration configuration
)
{
if (configuration == null)
throw new ArgumentNullException(nameof(configuration));
_logger = logger;
var apiToken = configuration.GetSection(Section)?[Key];
if (string.IsNullOrWhiteSpace(apiToken))
throw new IoCConfigurationException("API key", Section, Key);
_apiToken = apiToken;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation
)
{
// Check if the headers are not null, if so, initialize new headers
if (context.Options.Headers == null)
{
_logger.LogDebug("Adding gRPC option headers");
context.Options.WithHeaders(new Metadata());
}
// gRPC calls and responses can also include metadata that's similar to HTTP headers. This metadata is mostly
// invisible to gRPC itself and is passed through to be processed by your application code or middleware.
// Metadata is represented as key/value pairs, where the key is a string and the value is either a string or
// binary data. You don’t need to specify metadata in the .proto file.
// https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/metadata
var authorization = new Metadata.Entry(AuthorizationHeader, _apiToken);
// Check if the header already has an Authorization header within. For now we agreed on that no one is allowed
// to set this header. If we want to use this client for external API services as well, we need to look up if
// this is a good client to use and what changes it takes for this client to pair with another API then the Floof cloud
var setAuthorizationHeaderEntry = context.Options.Headers.Get(AuthorizationHeader);
if (setAuthorizationHeaderEntry != null)
{
_logger.LogWarning("Replacing the Authorization header by the configured Floof API key value.");
// Remove the header out of the options because we set the configured key
context.Options.Headers.Remove(setAuthorizationHeaderEntry);
}
// Add the header to the context.
context.Options.Headers.Add(authorization);
// replace the context with the authorization context
return base.AsyncUnaryCall(request, context, continuation);
}
}
}
在调用 return base.AsyncUnaryCall
时尝试传递新上下文 new ClientInterceptorContext
并设置所有需要的 headers 应该会有所帮助:
public class AuthorizationHeaderInterceptor : Interceptor
{
...
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
...
var headers = new Metadata();
headers.Add(new Metadata.Entry("Authorization", _token));
var newOptions = context.Options.WithHeaders(headers);
var newContext = new ClientInterceptorContext<TRequest, TResponse>(
context.Method,
context.Host,
newOptions);
return base.AsyncUnaryCall(request, newContext, continuation);
}
}
https://github.com/grpc/grpc-dotnet/issues/1255#issuecomment-811635583