Authentification et autorisation dans gRPC pour ASP.NET Core
Remarque
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.
Avertissement
Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.
Important
Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.
Pour la version actuelle, consultez la version .NET 9 de cet article.
Affichez ou téléchargez l’exemple de code (procédure de téléchargement)
Authentifier les utilisateurs appelant un service gRPC
gRPC peut être utilisé avec l’authentification ASP.NET Core pour associer un utilisateur à chaque appel.
Voici un exemple de Program.cs
qui utilise gRPC et l’authentification ASP.NET Core :
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapGrpcService<GreeterService>();
Remarque
L’ordre dans lequel vous inscrivez l’intergiciel d’authentification ASP.NET Core est important. Appelez toujours UseAuthentication
et UseAuthorization
après UseRouting
et avant UseEndpoints
.
Le mécanisme d’authentification utilisé par votre application lors d’un appel doit être configuré. La configuration de l’authentification est ajoutée dans Program.cs
et sera différente en fonction du mécanisme d’authentification utilisé par votre application.
Une fois l’authentification configurée, l’utilisateur est accessible dans les méthodes d’un service gRPC via le ServerCallContext
.
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
Authentification des jetons du porteur
Le client peut fournir un jeton d’accès pour l’authentification. Le serveur valide le jeton et l’utilise pour identifier l’utilisateur.
Sur le serveur, l’authentification par jeton du porteur est configurée à l’aide de l’intergiciel JWT Bearer.
Dans le client .NET gRPC, le jeton peut être envoyé avec des appels à l’aide de la collection Metadata
. Les entrées de la collection Metadata
sont envoyées avec un appel gRPC en tant qu’en-têtes HTTP :
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;
}
Définir le jeton du porteur avec CallCredentials
La configuration ChannelCredentials
sur un canal est une autre façon d’envoyer le jeton au service avec des appels gRPC. Un ChannelCredentials
peut inclure CallCredentials
, qui fournit un moyen de définir Metadata
automatiquement .
Avantages de l’utilisation de CallCredentials
:
- L’authentification est configurée de manière centralisée sur le canal. Le jeton n’a pas besoin d’être fourni manuellement à l’appel gRPC.
- Le rappel
CallCredentials.FromInterceptor
est asynchrone. Les informations d’identification de l’appel peuvent extraire un jeton d’informations d’identification depuis un système externe si nécessaire. Les méthodes asynchrones dans le rappel doivent utiliser leCancellationToken
surAuthInterceptorContext
.
Remarque
CallCredentials
sont appliqués uniquement si le canal est sécurisé avec TLS. L’envoi d’en-têtes d’authentification sur une connexion non sécurisée a des implications sur la sécurité et ne doit pas être effectué dans les environnements de production. Une application peut configurer un canal pour ignorer ce comportement et toujours utiliser CallCredentials
en définissant UnsafeUseInsecureChannelCallCredentials
sur un canal.
Dans l’exemple suivant, les informations d’identification configurent le canal pour envoyer le jeton à chaque appel gRPC :
private static GrpcChannel CreateAuthenticatedChannel(ITokenProvder tokenProvider)
{
var credentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await tokenProvider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
});
var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
return channel;
}
Jeton du porteur avec fabrique de clients gRPC
La fabrique de clients gRPC peut créer des clients qui envoient un jeton de porteur à l’aide de AddCallCredentials
. Cette méthode est disponible dans Grpc.Net.ClientFactory version 2.46.0 ou ultérieure.
Le délégué transmis à AddCallCredentials
est exécuté pour chaque appel gRPC :
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
});
L’injection de dépendances (DI) peut être combinée avec AddCallCredentials
. Une surcharge transmet IServiceProvider
au délégué, qui peut être utilisée pour obtenir un service construit à partir d’une DI à l’aide de services étendus et temporaires.
Prenons l’exemple d’une application qui a :
- Un
ITokenProvider
défini par l’utilisateur pour obtenir un jeton du porteur.ITokenProvider
est inscrit dans une DI avec une durée de vie étendue. - La fabrique de clients gRPC est configurée pour créer des clients injectés dans des services gRPC et des contrôleurs d’API web.
- Les appels gRPC doivent utiliser
ITokenProvider
pour obtenir un jeton du porteur.
public interface ITokenProvider
{
Task<string> GetTokenAsync(CancellationToken cancellationToken);
}
public class AppTokenProvider : ITokenProvider
{
private string _token;
public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
{
if (_token == null)
{
// App code to resolve the token here.
}
return _token;
}
}
builder.Services.AddScoped<ITokenProvider, AppTokenProvider>();
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials(async (context, metadata, serviceProvider) =>
{
var provider = serviceProvider.GetRequiredService<ITokenProvider>();
var token = await provider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
}));
Le code précédent :
- Définit
ITokenProvider
etAppTokenProvider
. Ces types gèrent la résolution du jeton d’authentification pour les appels gRPC. - Inscrit le type
AppTokenProvider
avec DI dans une durée de vie étendue.AppTokenProvider
met en cache le jeton afin que seul le premier appel dans l’étendue soit requis pour le calculer. - Inscrit le type
GreeterClient
auprès de la fabrique de clients. - Configure un
AddCallCredentials
pour ce client. Le délégué est exécuté chaque fois qu’un appel est effectué et ajoute le jeton retourné parITokenProvider
aux métadonnées.
Authentification par certificat client
Un client peut également fournir un certificat client pour l’authentification. L’authentification par certificat se produit au niveau TLS, bien avant qu’elle n’arrive à ASP.NET Core. Lorsque la requête arrive à ASP.NET Core, le package d’authentification de certificat client vous permet de résoudre le certificat en ClaimsPrincipal
.
Remarque
Configurez le serveur pour accepter des certificats clients. Pour plus d’informations sur l’acceptation des certificats clients dans Kestrel, IIS et Azure, consultez Configurer l’authentification par certificat dans ASP.NET Core.
Dans le client .NET gRPC, le certificat client est ajouté à HttpClientHandler
qui est ensuite utilisé pour créer le client 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
{
HttpHandler = handler
});
return new Ticketer.TicketerClient(channel);
}
Autres mécanismes d’authentification
De nombreux mécanismes d’authentification pris en charge par ASP.NET Core fonctionnent avec gRPC :
- Microsoft Entra ID
- Certificat client
- IdentityServer
- Jeton JWT
- OAuth 2.0
- OpenID Connect
- WS-Federation
Pour plus d’informations sur la configuration de l’authentification sur le serveur, consultez Authentification ASP.NET Core.
La configuration du client gRPC pour utiliser l’authentification dépend du mécanisme d’authentification que vous utilisez. Les exemples précédents de jeton du porteur et de certificat client montrent deux façons de configurer le client gRPC pour envoyer des métadonnées d’authentification avec des appels gRPC :
- Les clients gRPC fortement typés utilisent
HttpClient
en interne. L’authentification peut être configurée sur HttpClientHandler ou en ajoutant des instances HttpMessageHandler personnalisées àHttpClient
. - Chaque appel gRPC a un argument
CallOptions
facultatif. Les en-têtes personnalisés peuvent être envoyés à l’aide de la collection d’en-têtes de l’option.
Remarque
L’authentification Windows (NTLM/Kerberos/Negotiate) ne peut pas être utilisée avec gRPC. gRPC nécessite HTTP/2, et HTTP/2 ne prend pas en charge l’authentification Windows.
Autoriser les utilisateurs à accéder aux services et aux méthodes de service
Par défaut, toutes les méthodes d’un service peuvent être appelées par des utilisateurs non authentifiés. Pour exiger l’authentification, appliquez l’attribut [Authorize]
au service :
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}
Vous pouvez utiliser les arguments du constructeur et les propriétés de l’attribut [Authorize]
pour restreindre l’accès aux seuls utilisateurs correspondant à des stratégies d’autorisation spécifiques. Par exemple, si vous avez une stratégie d’autorisation personnalisée appelée MyAuthorizationPolicy
, assurez-vous que seuls les utilisateurs correspondant à cette stratégie peuvent accéder au service à l’aide du code suivant :
[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}
L’attribut [Authorize]
peut également être appliqué à des méthodes de service individuelles. Si l’utilisateur actuel ne correspond pas aux stratégies appliquées à la fois à la méthode et à la classe, une erreur est retournée à l’appelant :
[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) ..
}
}
Ressources supplémentaires
Affichez ou téléchargez l’exemple de code (procédure de téléchargement)
Authentifier les utilisateurs appelant un service gRPC
gRPC peut être utilisé avec l’authentification ASP.NET Core pour associer un utilisateur à chaque appel.
Voici un exemple de Startup.Configure
qui utilise gRPC et l’authentification ASP.NET Core :
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
Remarque
L’ordre dans lequel vous inscrivez l’intergiciel d’authentification ASP.NET Core est important. Appelez toujours UseAuthentication
et UseAuthorization
après UseRouting
et avant UseEndpoints
.
Le mécanisme d’authentification utilisé par votre application lors d’un appel doit être configuré. La configuration de l’authentification est ajoutée dans Startup.ConfigureServices
et sera différente en fonction du mécanisme d’authentification utilisé par votre application.
Une fois l’authentification configurée, l’utilisateur est accessible dans les méthodes d’un service gRPC via le ServerCallContext
.
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
Authentification des jetons du porteur
Le client peut fournir un jeton d’accès pour l’authentification. Le serveur valide le jeton et l’utilise pour identifier l’utilisateur.
Sur le serveur, l’authentification par jeton du porteur est configurée à l’aide de l’intergiciel JWT Bearer.
Dans le client .NET gRPC, le jeton peut être envoyé avec des appels à l’aide de la collection Metadata
. Les entrées de la collection Metadata
sont envoyées avec un appel gRPC en tant qu’en-têtes HTTP :
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;
}
Définir le jeton du porteur avec CallCredentials
La configuration ChannelCredentials
sur un canal est une autre façon d’envoyer le jeton au service avec des appels gRPC. Un ChannelCredentials
peut inclure CallCredentials
, qui fournit un moyen de définir Metadata
automatiquement .
Avantages de l’utilisation de CallCredentials
:
- L’authentification est configurée de manière centralisée sur le canal. Le jeton n’a pas besoin d’être fourni manuellement à l’appel gRPC.
- Le rappel
CallCredentials.FromInterceptor
est asynchrone. Les informations d’identification de l’appel peuvent extraire un jeton d’informations d’identification depuis un système externe si nécessaire. Les méthodes asynchrones dans le rappel doivent utiliser leCancellationToken
surAuthInterceptorContext
.
Remarque
CallCredentials
sont appliqués uniquement si le canal est sécurisé avec TLS. L’envoi d’en-têtes d’authentification sur une connexion non sécurisée a des implications sur la sécurité et ne doit pas être effectué dans les environnements de production. Une application peut configurer un canal pour ignorer ce comportement et toujours utiliser CallCredentials
en définissant UnsafeUseInsecureChannelCallCredentials
sur un canal.
Dans l’exemple suivant, les informations d’identification configurent le canal pour envoyer le jeton à chaque appel gRPC :
private static GrpcChannel CreateAuthenticatedChannel(ITokenProvder tokenProvider)
{
var credentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await tokenProvider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
});
var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
return channel;
}
Jeton du porteur avec fabrique de clients gRPC
La fabrique de clients gRPC peut créer des clients qui envoient un jeton de porteur à l’aide de AddCallCredentials
. Cette méthode est disponible dans Grpc.Net.ClientFactory version 2.46.0 ou ultérieure.
Le délégué transmis à AddCallCredentials
est exécuté pour chaque appel gRPC :
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
});
L’injection de dépendances (DI) peut être combinée avec AddCallCredentials
. Une surcharge transmet IServiceProvider
au délégué, qui peut être utilisée pour obtenir un service construit à partir d’une DI à l’aide de services étendus et temporaires.
Prenons l’exemple d’une application qui a :
- Un
ITokenProvider
défini par l’utilisateur pour obtenir un jeton du porteur.ITokenProvider
est inscrit dans une DI avec une durée de vie étendue. - La fabrique de clients gRPC est configurée pour créer des clients injectés dans des services gRPC et des contrôleurs d’API web.
- Les appels gRPC doivent utiliser
ITokenProvider
pour obtenir un jeton du porteur.
public interface ITokenProvider
{
Task<string> GetTokenAsync(CancellationToken cancellationToken);
}
public class AppTokenProvider : ITokenProvider
{
private string _token;
public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
{
if (_token == null)
{
// App code to resolve the token here.
}
return _token;
}
}
services.AddScoped<ITokenProvider, AppTokenProvider>();
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials(async (context, metadata, serviceProvider) =>
{
var provider = serviceProvider.GetRequiredService<ITokenProvider>();
var token = await provider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
}));
Le code précédent :
- Définit
ITokenProvider
etAppTokenProvider
. Ces types gèrent la résolution du jeton d’authentification pour les appels gRPC. - Inscrit le type
AppTokenProvider
avec DI dans une durée de vie étendue.AppTokenProvider
met en cache le jeton afin que seul le premier appel dans l’étendue soit requis pour le calculer. - Inscrit le type
GreeterClient
auprès de la fabrique de clients. - Configure un
AddCallCredentials
pour ce client. Le délégué est exécuté chaque fois qu’un appel est effectué et ajoute le jeton retourné parITokenProvider
aux métadonnées.
Authentification par certificat client
Un client peut également fournir un certificat client pour l’authentification. L’authentification par certificat se produit au niveau TLS, bien avant qu’elle n’arrive à ASP.NET Core. Lorsque la requête arrive à ASP.NET Core, le package d’authentification de certificat client vous permet de résoudre le certificat en ClaimsPrincipal
.
Remarque
Configurez le serveur pour accepter des certificats clients. Pour plus d’informations sur l’acceptation des certificats clients dans Kestrel, IIS et Azure, consultez Configurer l’authentification par certificat dans ASP.NET Core.
Dans le client .NET gRPC, le certificat client est ajouté à HttpClientHandler
qui est ensuite utilisé pour créer le client 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
{
HttpHandler = handler
});
return new Ticketer.TicketerClient(channel);
}
Autres mécanismes d’authentification
De nombreux mécanismes d’authentification pris en charge par ASP.NET Core fonctionnent avec gRPC :
- Microsoft Entra ID
- Certificat client
- IdentityServer
- Jeton JWT
- OAuth 2.0
- OpenID Connect
- WS-Federation
Pour plus d’informations sur la configuration de l’authentification sur le serveur, consultez Authentification ASP.NET Core.
La configuration du client gRPC pour utiliser l’authentification dépend du mécanisme d’authentification que vous utilisez. Les exemples précédents de jeton du porteur et de certificat client montrent deux façons de configurer le client gRPC pour envoyer des métadonnées d’authentification avec des appels gRPC :
- Les clients gRPC fortement typés utilisent
HttpClient
en interne. L’authentification peut être configurée sur HttpClientHandler ou en ajoutant des instances HttpMessageHandler personnalisées àHttpClient
. - Chaque appel gRPC a un argument
CallOptions
facultatif. Les en-têtes personnalisés peuvent être envoyés à l’aide de la collection d’en-têtes de l’option.
Remarque
L’authentification Windows (NTLM/Kerberos/Negotiate) ne peut pas être utilisée avec gRPC. gRPC nécessite HTTP/2, et HTTP/2 ne prend pas en charge l’authentification Windows.
Autoriser les utilisateurs à accéder aux services et aux méthodes de service
Par défaut, toutes les méthodes d’un service peuvent être appelées par des utilisateurs non authentifiés. Pour exiger l’authentification, appliquez l’attribut [Authorize]
au service :
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}
Vous pouvez utiliser les arguments du constructeur et les propriétés de l’attribut [Authorize]
pour restreindre l’accès aux seuls utilisateurs correspondant à des stratégies d’autorisation spécifiques. Par exemple, si vous avez une stratégie d’autorisation personnalisée appelée MyAuthorizationPolicy
, assurez-vous que seuls les utilisateurs correspondant à cette stratégie peuvent accéder au service à l’aide du code suivant :
[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}
L’attribut [Authorize]
peut également être appliqué à des méthodes de service individuelles. Si l’utilisateur actuel ne correspond pas aux stratégies appliquées à la fois à la méthode et à la classe, une erreur est retournée à l’appelant :
[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) ..
}
}
Méthodes d’extension d’autorisation
L’autorisation peut également être contrôlée en utilisant des méthodes d’extension d’autorisation ASP.NET Core standard, telles que AllowAnonymous
et RequireAuthorization
.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<TicketerService>().RequireAuthorization("Administrators");
app.Run();