ASP.NET Core のための gRPC での認証と承認
Note
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
作成者: James Newton-King
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
gRPC サービスを呼び出しているユーザーを認証する
gRPC を ASP.NET Core 認証と共に使用して、ユーザーを各呼び出しに関連付けることができます。
以下に、gRPC と ASP.NET Core 認証を使用する Program.cs
の例を示します。
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapGrpcService<GreeterService>();
Note
ASP.NET Core 認証ミドルウェアを登録する順序が重要です。 必ず UseRouting
の後に UseAuthentication
と UseAuthorization
を呼び出し、その後に UseEndpoints
を呼び出します。
呼び出し時にアプリによって使用される認証メカニズムは、構成する必要があります。 認証の構成は、Program.cs
に追加され、アプリで使用される認証メカニズムによって異なるものとなります。
認証が設定されると、ServerCallContext
を介して gRPC サービス メソッドでユーザーにアクセスできます。
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
ベアラー トークン認証
クライアントは認証のためのアクセス トークンを提供できます。 サーバーはトークンを検証し、それを使用してユーザーを識別します。
サーバーでは、JWT ベアラー ミドルウェアを使用してベアラー トークン認証が構成されます。
.NET gRPC クライアントでは、Metadata
コレクションを使用すれば、呼び出しでトークンを送信することができます。 Metadata
コレクション内のエントリは、gRPC 呼び出しで、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;
}
CallCredentials
を使用してベアラー トークンを設定する
チャネルで ChannelCredentials
を構成することは、gRPC 呼び出しを使用してトークンをサービスに送信するもう 1 つの方法です。 ChannelCredentials
には CallCredentials
を含めることができます。これにより、Metadata
を自動的に設定することができます。
CallCredentials
を使用する利点:
- 認証はチャネルで一元的に構成されます。 トークンを gRPC 呼び出しに手動で指定する必要はありません。
CallCredentials.FromInterceptor
コールバックは非同期です。 呼び出し資格情報では、必要に応じて外部システムから資格情報トークンをフェッチできます。 コールバック内の非同期メソッドでは、AuthInterceptorContext
でCancellationToken
を使用する必要があります。
注意
CallCredentials
はチャネルが TLS でセキュリティ保護されている場合にのみ適用されます。 セキュリティで保護されていない接続を経由した認証ヘッダーの送信はセキュリティに影響を及ぼすため、運用環境では実行しないでください。 アプリでは、チャネルで UnsafeUseInsecureChannelCallCredentials
を設定することで、この動作を無視し、常に CallCredentials
を使用するように、アプリを構成することができます。
次の例の資格情報では、すべての 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;
}
gRPC クライアント ファクトリでのベアラー トークン
gRPC クライアント ファクトリでは、AddCallCredentials
を使用してベアラー トークンを送信するクライアントを作成できます。 このメソッドは、Grpc.Net.ClientFactory バージョン 2.46.0 以降で使用できます。
AddCallCredentials
に渡されたデリゲートは、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;
});
依存関係の挿入 (DI) は、AddCallCredentials
と組み合わせることができます。 オーバーロードによって、IServiceProvider
がデリゲートに渡されます。これは、スコープ指定された、一時的なサービスを使用して DI から構築されたサービスを取得するために使用できます。
次のようなアプリを考えてみましょう。
- ベアラー トークンを取得するためのユーザー定義
ITokenProvider
。ITokenProvider
は、スコープ付きの有効期間を使って DI に登録されています。 - gRPC サービスと Web API コントローラーに挿入するクライアントを作成するように gRPC クライアント ファクトリが構成されています。
- gRPC 呼び出しには、ベアラー トークンを取得するために
ITokenProvider
を使う必要があります。
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}");
}));
上記のコードでは次の操作が行われます。
ITokenProvider
およびAppTokenProvider
を定義します。 これらの型によって、gRPC 呼び出しの認証トークンの解決が処理されます。- スコープ指定されたライフタイムの DI に
AppTokenProvider
型を登録します。 スコープ内の最初の呼び出しのみが計算で必要となるように、AppTokenProvider
によってトークンがキャッシュされます。 GreeterClient
型をクライアント ファクトリに登録します。- このクライアント用に、
AddCallCredentials
を構成します。 デリゲートは、呼び出しが行われるたびに実行されます。また、デリゲートを使用すると、ITokenProvider
によって返されたトークンがメタデータに追加されます。
クライアント証明書認証
別の方法として、クライアントから認証のためにクライアント証明書を提供することもできます。 証明書の認証は、ASP.NET Core に到達するずっと前に TLS レベルで実行されます。 要求が ASP.NET Core に到達すると、クライアント証明書の認証パッケージによって、証明書を ClaimsPrincipal
に解決できるようになります。
Note
クライアント証明書を受け入れるようにサーバーを構成します。 Kestrel、IIS、および Azure でのクライアント証明書の受け入れについては、「ASP.NET Core で証明書認証を構成する」を参照してください。
.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
{
HttpHandler = handler
});
return new Ticketer.TicketerClient(channel);
}
その他の認証メカニズム
ASP.NET Core でサポートされている多くの認証メカニズムを、gRPC で使用できます。
- Microsoft Entra ID
- クライアント証明書
- IdentityServer
- JWT トークン
- OAuth 2.0
- OpenID Connect
- WS-Federation
サーバーで認証を構成することの詳細については、ASP.NET Core 認証に関するページを参照してください。
認証を使用するための gRPC クライアントの構成は、使おうとしている認証メカニズムによって異なります。 前述したベアラー トークンとクライアント証明書の例では、gRPC 呼び出しで認証メタデータを送信するように gRPC クライアントを構成できるいくつかの方法を示しています。
- 厳密に型指定された gRPC クライアントは内部的に
HttpClient
を使用します。 HttpClientHandler 上で、またはカスタムの HttpMessageHandler インスタンスをHttpClient
に追加することで、認証を構成します。 - それぞれの gRPC 呼び出しに、省略可能な
CallOptions
引数があります。 オプションのヘッダー コレクションを使用して、カスタム ヘッダーを送信できます。
Note
gRPC で Windows 認証 (NTLM/Kerberos/ネゴシエート) を使用することはできません。 gRPC には HTTP/2 が必要で、HTTP/2 では Windows 認証がサポートされていません。
サービスやサービス メソッドにアクセスするユーザーを承認する
既定では、認証されていないユーザーが、サービスのすべてのメソッドを呼び出すことができます。 認証を要求するには、サービスに [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) ..
}
}
その他の技術情報
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
gRPC サービスを呼び出しているユーザーを認証する
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>();
});
}
Note
ASP.NET Core 認証ミドルウェアを登録する順序が重要です。 必ず UseRouting
の後に UseAuthentication
と UseAuthorization
を呼び出し、その後に UseEndpoints
を呼び出します。
呼び出し時にアプリによって使用される認証メカニズムは、構成する必要があります。 認証の構成は、Startup.ConfigureServices
に追加され、アプリで使用される認証メカニズムによって異なるものとなります。
認証が設定されると、ServerCallContext
を介して gRPC サービス メソッドでユーザーにアクセスできます。
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
ベアラー トークン認証
クライアントは認証のためのアクセス トークンを提供できます。 サーバーはトークンを検証し、それを使用してユーザーを識別します。
サーバーでは、JWT ベアラー ミドルウェアを使用してベアラー トークン認証が構成されます。
.NET gRPC クライアントでは、Metadata
コレクションを使用すれば、呼び出しでトークンを送信することができます。 Metadata
コレクション内のエントリは、gRPC 呼び出しで、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;
}
CallCredentials
を使用してベアラー トークンを設定する
チャネルで ChannelCredentials
を構成することは、gRPC 呼び出しを使用してトークンをサービスに送信するもう 1 つの方法です。 ChannelCredentials
には CallCredentials
を含めることができます。これにより、Metadata
を自動的に設定することができます。
CallCredentials
を使用する利点:
- 認証はチャネルで一元的に構成されます。 トークンを gRPC 呼び出しに手動で指定する必要はありません。
CallCredentials.FromInterceptor
コールバックは非同期です。 呼び出し資格情報では、必要に応じて外部システムから資格情報トークンをフェッチできます。 コールバック内の非同期メソッドでは、AuthInterceptorContext
でCancellationToken
を使用する必要があります。
注意
CallCredentials
はチャネルが TLS でセキュリティ保護されている場合にのみ適用されます。 セキュリティで保護されていない接続を経由した認証ヘッダーの送信はセキュリティに影響を及ぼすため、運用環境では実行しないでください。 アプリでは、チャネルで UnsafeUseInsecureChannelCallCredentials
を設定することで、この動作を無視し、常に CallCredentials
を使用するように、アプリを構成することができます。
次の例の資格情報では、すべての 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;
}
gRPC クライアント ファクトリでのベアラー トークン
gRPC クライアント ファクトリでは、AddCallCredentials
を使用してベアラー トークンを送信するクライアントを作成できます。 このメソッドは、Grpc.Net.ClientFactory バージョン 2.46.0 以降で使用できます。
AddCallCredentials
に渡されたデリゲートは、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;
});
依存関係の挿入 (DI) は、AddCallCredentials
と組み合わせることができます。 オーバーロードによって、IServiceProvider
がデリゲートに渡されます。これは、スコープ指定された、一時的なサービスを使用して DI から構築されたサービスを取得するために使用できます。
次のようなアプリを考えてみましょう。
- ベアラー トークンを取得するためのユーザー定義
ITokenProvider
。ITokenProvider
は、スコープ付きの有効期間を使って DI に登録されています。 - gRPC サービスと Web API コントローラーに挿入するクライアントを作成するように gRPC クライアント ファクトリが構成されています。
- gRPC 呼び出しには、ベアラー トークンを取得するために
ITokenProvider
を使う必要があります。
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}");
}));
上記のコードでは次の操作が行われます。
ITokenProvider
およびAppTokenProvider
を定義します。 これらの型によって、gRPC 呼び出しの認証トークンの解決が処理されます。- スコープ指定されたライフタイムの DI に
AppTokenProvider
型を登録します。 スコープ内の最初の呼び出しのみが計算で必要となるように、AppTokenProvider
によってトークンがキャッシュされます。 GreeterClient
型をクライアント ファクトリに登録します。- このクライアント用に、
AddCallCredentials
を構成します。 デリゲートは、呼び出しが行われるたびに実行されます。また、デリゲートを使用すると、ITokenProvider
によって返されたトークンがメタデータに追加されます。
クライアント証明書認証
別の方法として、クライアントから認証のためにクライアント証明書を提供することもできます。 証明書の認証は、ASP.NET Core に到達するずっと前に TLS レベルで実行されます。 要求が ASP.NET Core に到達すると、クライアント証明書の認証パッケージによって、証明書を ClaimsPrincipal
に解決できるようになります。
Note
クライアント証明書を受け入れるようにサーバーを構成します。 Kestrel、IIS、および Azure でのクライアント証明書の受け入れについては、「ASP.NET Core で証明書認証を構成する」を参照してください。
.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
{
HttpHandler = handler
});
return new Ticketer.TicketerClient(channel);
}
その他の認証メカニズム
ASP.NET Core でサポートされている多くの認証メカニズムを、gRPC で使用できます。
- Microsoft Entra ID
- クライアント証明書
- IdentityServer
- JWT トークン
- OAuth 2.0
- OpenID Connect
- WS-Federation
サーバーで認証を構成することの詳細については、ASP.NET Core 認証に関するページを参照してください。
認証を使用するための gRPC クライアントの構成は、使おうとしている認証メカニズムによって異なります。 前述したベアラー トークンとクライアント証明書の例では、gRPC 呼び出しで認証メタデータを送信するように gRPC クライアントを構成できるいくつかの方法を示しています。
- 厳密に型指定された gRPC クライアントは内部的に
HttpClient
を使用します。 HttpClientHandler 上で、またはカスタムの HttpMessageHandler インスタンスをHttpClient
に追加することで、認証を構成します。 - それぞれの gRPC 呼び出しに、省略可能な
CallOptions
引数があります。 オプションのヘッダー コレクションを使用して、カスタム ヘッダーを送信できます。
Note
gRPC で Windows 認証 (NTLM/Kerberos/ネゴシエート) を使用することはできません。 gRPC には HTTP/2 が必要で、HTTP/2 では Windows 認証がサポートされていません。
サービスやサービス メソッドにアクセスするユーザーを承認する
既定では、認証されていないユーザーが、サービスのすべてのメソッドを呼び出すことができます。 認証を要求するには、サービスに [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) ..
}
}
認可拡張メソッド
認可は、AllowAnonymous
や RequireAuthorization
などの標準の ASP.NET Core 認可拡張メソッドを使用して制御することもできます。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<TicketerService>().RequireAuthorization("Administrators");
app.Run();
その他のリソース
ASP.NET Core