gRPC for ASP.NET Core 中的身份验证和授权Authentication and authorization in gRPC for ASP.NET Core
本文内容
对调用 gRPC 服务的用户进行身份验证Authenticate users calling a gRPC service
gRPC 可与 ASP.NET Core 身份验证配合使用,将用户与每个调用关联。
以下是使用 gRPC 和 ASP.NET Core 身份验证的 Startup.Configure
的示例:
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
备注
注册 ASP.NET Core 身份验证中间件的顺序很重要。始终在 UseRouting
之后和 UseEndpoints
之前调用 UseAuthentication
和 UseAuthorization
。
应用在调用期间使用的身份验证机制需要进行配置。身份验证配置已添加到 Startup.ConfigureServices
中,并因应用使用的身份验证机制而异。有关如何保护 ASP.NET Core 应用的示例,请参阅身份验证示例。
设置身份验证后,可通过 ServerCallContext
使用 gRPC 服务方法访问用户。
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
持有者令牌身份验证Bearer token authentication
客户端可提供用于身份验证的访问令牌。服务器验证令牌并使用它来标识用户。
在服务器上,使用 JWT 持有者中间件配置持有者令牌身份验证。
在 .NET gRPC 客户端中,令牌可作为标头与调用一起发送:
public bool DoAuthenticatedCall(
Ticketer.TicketerClient client, string token)
{
var headers = new Metadata();
headers.Add("Authorization", $"Bearer {token}");
var request = new BuyTicketsRequest { Count = 1 };
var response = await client.BuyTicketsAsync(request, headers);
return response.Success;
}
在通道上配置 ChannelCredentials
是通过 gRPC 调用将令牌发送到服务的备用方法。凭据在每次进行 gRPC 调用时运行,因而无需在多个位置编写代码用于自行传递令牌。
以下示例中的凭据将通道配置为随每个 gRPC 调用发送令牌:
private static GrpcChannel CreateAuthenticatedChannel(string address)
{
var credentials = CallCredentials.FromInterceptor((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
});
// SslCredentials is used here because this channel is using TLS.
// CallCredentials can't be used with ChannelCredentials.Insecure on non-TLS channels.
var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
return channel;
}
客户端证书身份验证Client certificate authentication
客户端还可以提供用于身份验证的客户端证书。证书身份验证在 TLS 级别发生,远在到达 ASP.NET Core 之前。当请求进入 ASP.NET Core 时,可借助客户端证书身份验证包将证书解析为 ClaimsPrincipal
。
备注
需要将主机配置为接受客户端证书。有关在 Kestrel、IIS 和 Azure 中接受客户端证书的信息,请参阅将主机配置为要求提供证书。
在 .NET gRPC 客户端中,客户端证书已添加到 HttpClientHandler
中,后者之后用于创建 gRPC 客户端:
public Ticketer.TicketerClient CreateClientWithCert(
string baseAddress,
X509Certificate2 certificate)
{
// Add client cert to the handler
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
// Create the gRPC channel
var channel = GrpcChannel.ForAddress(baseAddress, new GrpcChannelOptions
{
HttpClient = new HttpClient(handler)
});
return new Ticketer.TicketerClient(channel);
}
其他身份验证机制Other authentication mechanisms
许多 ASP.NET Core 支持的身份验证机制都可以与 gRPC 配合使用:
- Azure Active Directory
- 客户端证书
- IdentityServer
- JWT 令牌
- OAuth 2.0
- OpenID Connect
- WS-Federation
有关在服务器上配置身份验证的详细信息,请参阅 ASP.NET Core 身份验证。
将 gRPC 客户端配置为使用身份验证取决于使用的身份验证机制。之前的持有者令牌和客户端证书示例演示可将 gRPC 客户端配置为通过 gRPC 调用发送身份验证元数据的几种方法:
- 强类型 gRPC 客户端在内部使用
HttpClient
。可在 HttpClientHandler 上配置身份验证,也可通过向HttpClient
添加自定义 HttpMessageHandler 实例进行配置。 - 每个 gRPC 调用都有一个可选的
CallOptions
参数。可使用该选项的标头集合发送自定义标头。
备注
Windows 身份验证(NTLM/Kerberos/协商)不能与 gRPC 配合使用。gRPC 需要 HTTP/2,而 HTTP/2 不支持 Windows 身份验证。
授权用户访问服务和服务方法Authorize users to access services and service methods
默认情况下,未经身份验证的用户可以调用服务中的所有方法。若要要求进行身份验证,请将 [Authorize]
特性应用于服务:
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}
可使用 [Authorize]
特性的构造函数参数和属性将访问权限仅限于匹配特定授权策略的用户。例如,如果有一个名为 MyAuthorizationPolicy
的自定义授权策略,请使用以下代码确保仅匹配该策略的用户才能访问服务:
[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}
各个服务方法也可以应用 [Authorize]
特性。如果当前用户与同时应用于方法和类的策略不匹配,则会向调用方返回错误:
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
public override Task<AvailableTicketsResponse> GetAvailableTickets(
Empty request, ServerCallContext context)
{
// ... buy tickets for the current user ...
}
[Authorize("Administrators")]
public override Task<BuyTicketsResponse> RefundTickets(
BuyTicketsRequest request, ServerCallContext context)
{
// ... refund tickets (something only Administrators can do) ..
}
}