ASP.NET gRPC 服务的核心 MVC 过滤器模拟

ASP.NET Core MVC filter analogue for gRPC service

我在 ASP.NET Core 3.0 上有一个现有的 REST API 运行。它使用 MVC 过滤器根据 header 值和 returns 错误执行授权检查,以防授权失败,这样请求就不会传递给控制器​​。

现在,我正在试验 gRPC 并尝试将此 API 移植到 gRPC 服务。但是,我没有看到任何明显的解决方案可以作为 MVC 过滤器的替代品。

是否有某种方法可以实现类似的授权检查功能,也许使用 metadata

这将有略微不同的答案,具体取决于您是否使用 Grpc.Core, which is a wrapper around the C GRPC library initially developed at Google, which has been available for a while and supports a variety of .Net targets (including Framework), or if you're using the new Grpc.AspNetCore,它随 .Net Core 3.0 一起启动并构建在 Kestrel 和 ASP.NET 核心内部。

Grpc.Core

对于 Grpc.Core,您可能希望将 header 值作为元数据传递,然后创建一个 server-side Interceptor to handle the metadata and the request. You can also consider using the AsyncAuthInterceptor,但是客户端的核心 Grpc 实现不会发送凭据不安全的(non-TLS)连接。

Grpc.AspNetCore

Grpc.AspNetCore 建立在 ASP.NET 和 can use ASP.NET middleware 之上,包括默认的 ASP.NET 身份验证。如果可以将过滤器转换为中间件,则可以在两个实现之间共享身份验证。

对于 MVC 和 gRpc,它们是不同的。 gRpc 下不存在 ActionFilter。

如果您想为所有操作应用检查请求 header,您可以尝试在 app.UseEndpoints 之前实现您的自定义中间件并检查请求 header。

换一种方式,您可以尝试 Policy 如下所示:

  1. GrpcRequireemntGrpcHandler

    public class GrpcRequireemnt : IAuthorizationRequirement
    { 
    
    }
    public class GrpcHandler : AuthorizationHandler<GrpcRequireemnt>
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
    
        public GrpcHandler(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, GrpcRequireemnt requirement)
        {
    
            var headers = _httpContextAccessor.HttpContext.Request.Headers;
            StringValues token;
            if (!headers.TryGetValue("token", out token))
            {
                context.Fail();
                return Task.CompletedTask;
            }
            context.Succeed(requirement);
            return Task.CompletedTask;
    
        }
    }
    
  2. 注册所需服务

    services.AddAuthorization(options =>
    {
        options.AddPolicy("TokenAuthorize", policy =>
        {                   
            policy.AddRequirements(new GrpcRequireemnt());
        });
    });
    services.AddHttpContextAccessor();
    services.AddSingleton<IAuthorizationHandler, GrpcHandler>();
    
  3. 用例

    [Authorize("TokenAuthorize")]
    public override Task<BuyTicketsResponse> BuyTickets(BuyTicketsRequest request, ServerCallContext context)
    {
        var user = context.GetHttpContext().User;
    
        return Task.FromResult(new BuyTicketsResponse
        {
            Success = _ticketRepository.BuyTickets(user.Identity.Name!, request.Count)
        });
    }