Ověřování a autorizace v gRPC pro ASP.NET Core

Autor: James Newton-King

Zobrazení nebo stažení ukázkového kódu (postup stažení)

Ověřování uživatelů, kteří volají službu gRPC

GRPC lze použít s ověřováním ASP.NET Core k přidružení uživatele k jednotlivým voláním.

Následuje příklad Program.cs použití gRPC a ověřování ASP.NET Core:

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapGrpcService<GreeterService>();

Poznámka:

Pořadí, ve kterém zaregistrujete middleware ověřování ASP.NET Core, záleží. Vždy zavolat UseAuthentication a za a před UseRoutingUseEndpoints.UseAuthorization

Ověřovací mechanismus, který vaše aplikace používá během volání, je potřeba nakonfigurovat. Konfigurace ověřování se přidá Program.cs a bude se lišit v závislosti na mechanismu ověřování, který vaše aplikace používá.

Po nastavení ověřování je uživatel přístupný v metodách služby gRPC prostřednictvím ServerCallContextmetody .

public override Task<BuyTicketsResponse> BuyTickets(
    BuyTicketsRequest request, ServerCallContext context)
{
    var user = context.GetHttpContext().User;

    // ... access data from ClaimsPrincipal ...
}

Ověřování nosný token

Klient může poskytnout přístupový token pro ověřování. Server token ověří a použije ho k identifikaci uživatele.

Na serveru se ověřování nosných tokenů konfiguruje pomocí middlewaru JWT Bearer.

V klientovi .NET gRPC lze token odeslat s voláními pomocí Metadata kolekce. Položky v kolekci Metadata se odesílají s voláním gRPC jako hlavičky 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;
}

Nastavení nosné tokeny pomocí CallCredentials

Konfigurace ChannelCredentials v kanálu představuje alternativní způsob odeslání tokenu do služby pomocí volání gRPC. A ChannelCredentials může zahrnovat CallCredentials, které poskytují způsob, jak automaticky nastavit Metadata.

Výhody použití CallCredentials:

  • Ověřování je centrálně nakonfigurované v kanálu. Token nemusí být ručně poskytnut volání gRPC.
  • CallCredentials.FromInterceptor Zpětné volání je asynchronní. V případě potřeby může volání přihlašovacích údajů načíst token přihlašovacích údajů z externího systému. Asynchronní metody uvnitř zpětného volání by měly používat on CancellationTokenAuthInterceptorContext.

Poznámka:

CallCredentials jsou použity pouze v případě, že je kanál zabezpečený protokolem TLS. Odesílání hlaviček ověřování přes nezabezpečené připojení má vliv na zabezpečení a nemělo by se provádět v produkčních prostředích. Aplikace může nakonfigurovat kanál tak, aby toto chování ignoroval a vždy ho používal CallCredentials nastavením UnsafeUseInsecureChannelCallCredentials kanálu.

Přihlašovací údaje v následujícím příkladu konfigurují kanál tak, aby odesílal token s každým voláním 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;
}

Nosný token s klientskou továrnou gRPC

Klientská továrna gRPC může vytvářet klienty, kteří odesílají nosný token pomocí AddCallCredentials. Tato metoda je k dispozici v Grpc.Net.ClientFactory verze 2.46.0 nebo novější.

Delegát předaný je AddCallCredentials spuštěn pro každé volání 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;
    });

Injektáž závislostí (DI) lze kombinovat s AddCallCredentials. Přetížení se předá IServiceProvider delegátu, který lze použít k získání služby vytvořené z DI pomocí vymezených a přechodných služeb.

Představte si aplikaci, která má:

  • Uživatelem definovaný ITokenProvider pro získání nosné tokeny. ITokenProvider aplikace is registered in DI with a scoped lifetime.
  • Klientská továrna gRPC je nakonfigurovaná tak, aby vytvářela klienty vložené do služeb gRPC a řadičů webového rozhraní API.
  • Volání gRPC by se měla použít ITokenProvider k získání nosný token.
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}");
    }));

Předchozí kód:

  • ITokenProvider Definuje a AppTokenProvider. Tyto typy zpracovávají překlad ověřovacího tokenu pro volání gRPC.
  • Zaregistruje AppTokenProvider typ v oboru životnosti pomocí DI. AppTokenProvider uloží token do mezipaměti, aby se k výpočtu vyžadovalo pouze první volání v oboru.
  • Zaregistruje typ v GreeterClient klientské továrně.
  • Konfiguruje AddCallCredentials pro tohoto klienta. Delegát se spustí při každém volání a přidá token vrácený ITokenProvider do metadat.

Ověřování klientských certifikátů

Klient může případně poskytnout klientský certifikát pro ověřování. Ověřování certifikátů probíhá na úrovni protokolu TLS, dlouho předtím, než se někdy dostane k ASP.NET Core. Když požadavek zadá ASP.NET Core, balíček ověřování klientských certifikátů umožňuje přeložit certifikát na ClaimsPrincipal.

Poznámka:

Nakonfigurujte server tak, aby přijímal klientské certifikáty. Informace o přijetí klientských certifikátů ve Kestrelslužbě , IIS a Azure najdete v tématu Konfigurace ověřování certifikátů v ASP.NET Core.

V klientovi .NET gRPC se do klienta přidá klientský certifikát, který HttpClientHandler se pak použije k vytvoření klienta 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);
}

Další mechanismy ověřování

Mnoho ASP.NET core podporovaných ověřovacích mechanismů funguje s gRPC:

  • Microsoft Entra ID
  • Klientský certifikát
  • IdentityServer
  • JWT Token
  • OAuth 2.0
  • OpenID Connect
  • WS-Federation

Další informace o konfiguraci ověřování na serveru najdete v tématu ASP.NET Základní ověřování.

Konfigurace klienta gRPC pro použití ověřování bude záviset na mechanismu ověřování, který používáte. Předchozí nosný token a příklady klientských certifikátů ukazují několik způsobů, jak lze klienta gRPC nakonfigurovat tak, aby odesílala metadata ověřování pomocí volání gRPC:

  • Klienti gRPC silného typu používají HttpClient interně. Ověřování lze nakonfigurovat na HttpClientHandlernebo přidáním vlastních HttpMessageHandler instancí do .HttpClient
  • Každé volání gRPC má volitelný CallOptions argument. Vlastní hlavičky je možné odeslat pomocí kolekce hlaviček možnosti.

Poznámka:

Ověřování systému Windows (NTLM/ Kerberos/Negotiate) se nedá použít s gRPC. gRPC vyžaduje HTTP/2 a HTTP/2 nepodporuje ověřování systému Windows.

Autorizace uživatelů pro přístup ke službám a metodám služeb

Ve výchozím nastavení můžou všechny metody ve službě volat neověřené uživatele. Pokud chcete vyžadovat ověření, použijte [Authorize] atribut pro službu:

[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}

Pomocí argumentů a vlastností konstruktoru atributu [Authorize] můžete omezit přístup pouze na uživatele, kteří odpovídají konkrétním zásadám autorizace. Pokud máte například volanou MyAuthorizationPolicyvlastní autorizační zásadu, ujistěte se, že k této službě mají přístup pouze uživatelé odpovídající této zásadě, a to pomocí následujícího kódu:

[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}

Jednotlivé metody služby mohou mít [Authorize] také použitý atribut. Pokud aktuální uživatel neodpovídá zásadám použitým pro metodu i třídu, vrátí se volajícímu chyba:

[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) ..
    }
}

Další materiály

Zobrazení nebo stažení ukázkového kódu (postup stažení)

Ověřování uživatelů, kteří volají službu gRPC

GRPC lze použít s ověřováním ASP.NET Core k přidružení uživatele k jednotlivým voláním.

Následuje příklad Startup.Configure použití gRPC a ověřování ASP.NET Core:

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>();
    });
}

Poznámka:

Pořadí, ve kterém zaregistrujete middleware ověřování ASP.NET Core, záleží. Vždy zavolat UseAuthentication a za a před UseRoutingUseEndpoints.UseAuthorization

Ověřovací mechanismus, který vaše aplikace používá během volání, je potřeba nakonfigurovat. Konfigurace ověřování se přidá Startup.ConfigureServices a bude se lišit v závislosti na mechanismu ověřování, který vaše aplikace používá.

Po nastavení ověřování je uživatel přístupný v metodách služby gRPC prostřednictvím ServerCallContextmetody .

public override Task<BuyTicketsResponse> BuyTickets(
    BuyTicketsRequest request, ServerCallContext context)
{
    var user = context.GetHttpContext().User;

    // ... access data from ClaimsPrincipal ...
}

Ověřování nosný token

Klient může poskytnout přístupový token pro ověřování. Server token ověří a použije ho k identifikaci uživatele.

Na serveru se ověřování nosných tokenů konfiguruje pomocí middlewaru JWT Bearer.

V klientovi .NET gRPC lze token odeslat s voláními pomocí Metadata kolekce. Položky v kolekci Metadata se odesílají s voláním gRPC jako hlavičky 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;
}

Nastavení nosné tokeny pomocí CallCredentials

Konfigurace ChannelCredentials v kanálu představuje alternativní způsob odeslání tokenu do služby pomocí volání gRPC. A ChannelCredentials může zahrnovat CallCredentials, které poskytují způsob, jak automaticky nastavit Metadata.

Výhody použití CallCredentials:

  • Ověřování je centrálně nakonfigurované v kanálu. Token nemusí být ručně poskytnut volání gRPC.
  • CallCredentials.FromInterceptor Zpětné volání je asynchronní. V případě potřeby může volání přihlašovacích údajů načíst token přihlašovacích údajů z externího systému. Asynchronní metody uvnitř zpětného volání by měly používat on CancellationTokenAuthInterceptorContext.

Poznámka:

CallCredentials jsou použity pouze v případě, že je kanál zabezpečený protokolem TLS. Odesílání hlaviček ověřování přes nezabezpečené připojení má vliv na zabezpečení a nemělo by se provádět v produkčních prostředích. Aplikace může nakonfigurovat kanál tak, aby toto chování ignoroval a vždy ho používal CallCredentials nastavením UnsafeUseInsecureChannelCallCredentials kanálu.

Přihlašovací údaje v následujícím příkladu konfigurují kanál tak, aby odesílal token s každým voláním 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;
}

Nosný token s klientskou továrnou gRPC

Klientská továrna gRPC může vytvářet klienty, kteří odesílají nosný token pomocí AddCallCredentials. Tato metoda je k dispozici v Grpc.Net.ClientFactory verze 2.46.0 nebo novější.

Delegát předaný je AddCallCredentials spuštěn pro každé volání 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;
    });

Injektáž závislostí (DI) lze kombinovat s AddCallCredentials. Přetížení se předá IServiceProvider delegátu, který lze použít k získání služby vytvořené z DI pomocí vymezených a přechodných služeb.

Představte si aplikaci, která má:

  • Uživatelem definovaný ITokenProvider pro získání nosné tokeny. ITokenProvider aplikace is registered in DI with a scoped lifetime.
  • Klientská továrna gRPC je nakonfigurovaná tak, aby vytvářela klienty vložené do služeb gRPC a řadičů webového rozhraní API.
  • Volání gRPC by se měla použít ITokenProvider k získání nosný token.
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}");
    }));

Předchozí kód:

  • ITokenProvider Definuje a AppTokenProvider. Tyto typy zpracovávají překlad ověřovacího tokenu pro volání gRPC.
  • Zaregistruje AppTokenProvider typ v oboru životnosti pomocí DI. AppTokenProvider uloží token do mezipaměti, aby se k výpočtu vyžadovalo pouze první volání v oboru.
  • Zaregistruje typ v GreeterClient klientské továrně.
  • Konfiguruje AddCallCredentials pro tohoto klienta. Delegát se spustí při každém volání a přidá token vrácený ITokenProvider do metadat.

Ověřování klientských certifikátů

Klient může případně poskytnout klientský certifikát pro ověřování. Ověřování certifikátů probíhá na úrovni protokolu TLS, dlouho předtím, než se někdy dostane k ASP.NET Core. Když požadavek zadá ASP.NET Core, balíček ověřování klientských certifikátů umožňuje přeložit certifikát na ClaimsPrincipal.

Poznámka:

Nakonfigurujte server tak, aby přijímal klientské certifikáty. Informace o přijetí klientských certifikátů ve Kestrelslužbě , IIS a Azure najdete v tématu Konfigurace ověřování certifikátů v ASP.NET Core.

V klientovi .NET gRPC se do klienta přidá klientský certifikát, který HttpClientHandler se pak použije k vytvoření klienta 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);
}

Další mechanismy ověřování

Mnoho ASP.NET core podporovaných ověřovacích mechanismů funguje s gRPC:

  • Microsoft Entra ID
  • Klientský certifikát
  • IdentityServer
  • JWT Token
  • OAuth 2.0
  • OpenID Connect
  • WS-Federation

Další informace o konfiguraci ověřování na serveru najdete v tématu ASP.NET Základní ověřování.

Konfigurace klienta gRPC pro použití ověřování bude záviset na mechanismu ověřování, který používáte. Předchozí nosný token a příklady klientských certifikátů ukazují několik způsobů, jak lze klienta gRPC nakonfigurovat tak, aby odesílala metadata ověřování pomocí volání gRPC:

  • Klienti gRPC silného typu používají HttpClient interně. Ověřování lze nakonfigurovat na HttpClientHandlernebo přidáním vlastních HttpMessageHandler instancí do .HttpClient
  • Každé volání gRPC má volitelný CallOptions argument. Vlastní hlavičky je možné odeslat pomocí kolekce hlaviček možnosti.

Poznámka:

Ověřování systému Windows (NTLM/ Kerberos/Negotiate) se nedá použít s gRPC. gRPC vyžaduje HTTP/2 a HTTP/2 nepodporuje ověřování systému Windows.

Autorizace uživatelů pro přístup ke službám a metodám služeb

Ve výchozím nastavení můžou všechny metody ve službě volat neověřené uživatele. Pokud chcete vyžadovat ověření, použijte [Authorize] atribut pro službu:

[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}

Pomocí argumentů a vlastností konstruktoru atributu [Authorize] můžete omezit přístup pouze na uživatele, kteří odpovídají konkrétním zásadám autorizace. Pokud máte například volanou MyAuthorizationPolicyvlastní autorizační zásadu, ujistěte se, že k této službě mají přístup pouze uživatelé odpovídající této zásadě, a to pomocí následujícího kódu:

[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}

Jednotlivé metody služby mohou mít [Authorize] také použitý atribut. Pokud aktuální uživatel neodpovídá zásadám použitým pro metodu i třídu, vrátí se volajícímu chyba:

[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) ..
    }
}

Další materiály