ASP.NET Core: Xác thực và ủy quyền trong gRPC cho ASP.NET Core


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Trong bài viết này

  1. Xác thực người dùng gọi dịch vụ gRPC
  2. Ủy quyền cho người dùng truy cập dịch vụ và phương thức dịch vụ
  3. Tài nguyên bổ sung

Xem hoặc tải xuống code mẫu (cách tải xuống)

Xác thực người dùng gọi dịch vụ gRPC

gRPC có thể được sử dụng với xác thực ASP.NET Core để liên kết người dùng với mỗi lời gọi.

Sau đây là ví dụ Program.cs sử dụng xác thực gRPC và ASP.NET Core:

app.UseRouting();

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

app.MapGrpcService<GreeterService>();

Ghi chú

Thứ tự bạn đăng ký middleware xác thực ASP.NET Core rất quan trọng. Luôn luôn gọi UseAuthentication và UseAuthorizationsau UseRouting và trước UseEndpoints.

Cơ chế xác thực mà ứng dụng của bạn sử dụng trong lời gọi cần phải được định cấu hình. Cấu hình xác thực được thêm vào Program.cs và sẽ khác nhau tùy thuộc vào cơ chế xác thực mà ứng dụng của bạn sử dụng. Để biết ví dụ về cách bảo mật ứng dụng ASP.NET Core, hãy xem Mẫu xác thực.

Sau khi xác thực đã được thiết lập, người dùng có thể được truy cập vào các phương thức dịch vụ gRPC thông qua file ServerCallContext.

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

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

Xác thực mã thông báo mang

Máy khách có thể cung cấp mã thông báo truy cập để xác thực. Máy chủ xác thực mã thông báo và sử dụng nó để nhận dạng người dùng.

Trên máy chủ, xác thực mã thông báo mang được định cấu hình bằng middleware JWT Bearer.

Trong ứng dụng khách .NET gRPC, mã thông báo có thể được gửi cùng với các lời gọi bằng cách sử dụng collection Metadata. Các mục trong collection Metadata được gửi với lệnh gọi gRPC dưới dạng header 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;
}

Đặt mã thông báo mang với CallCredentials

Định cấu hình ChannelCredentials trên kênh là một cách khác để gửi mã thông báo đến dịch vụ bằng lệnh gọi gRPC. ChannelCredentials có thể bao gồm CallCredentials, cung cấp cách tự động thiết đặt Metadata.

Lợi ích của việc sử dụng CallCredentials:

  • Xác thực được cấu hình tập trung trên kênh. Mã thông báo không cần phải được cung cấp theo cách thủ công cho lệnh gọi gRPC.
  • Gọi lại CallCredentials.FromInterceptor là không đồng bộ. Thông tin xác thực lời gọi có thể tìm nạp mã thông tin xác thực từ hệ thống bên ngoài nếu được yêu cầu. Các phương thức không đồng bộ bên trong lệnh gọi lại nên sử dụng CancellationTokenon AuthInterceptorContext.

Ghi chú

CallCredentials chỉ được áp dụng nếu kênh được bảo mật bằng TLS. Việc gửi header xác thực qua kết nối không an toàn có liên quan đến bảo mật và không nên thực hiện trong môi trường production. Ứng dụng có thể định cấu hình kênh để bỏ qua hành vi này và luôn sử dụng CallCredentials bằng cách thiết đặt UnsafeUseInsecureChannelCallCredentials trên kênh.

Thông tin xác thực trong ví dụ sau sẽ định cấu hình kênh để gửi mã thông báo với mỗi lệnh gọi 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;
}

Mã thông báo mang với factory máy khách gRPC

Factory máy khách gRPC có thể tạo các ứng dụng khách gửi mã thông báo mang bằng cách sử dụng AddCallCredentials. Phương pháp này có sẵn trong Grpc.Net.ClientFactory phiên bản 2.46.0 trở lên.

Delegate được truyền tới AddCallCredentials sẽ được thực thi cho mỗi lệnh gọi 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;
    });

Việc chèn phụ thuộc (DI) có thể được kết hợp với AddCallCredentials. Quá tải (overloading) sẽ truyền IServiceProvider đến delegate, delegate này có thể được sử dụng để xây dựng dịch vụ từ DI bằng cách sử dụng các dịch vụ có phạm vi và nhất thời (transient).

Hãy xem xét một ứng dụng có:

  • ITokenProvider do người dùng định nghĩa để nhận mã thông báo mang. ITokenProvider được đăng ký trong DI với thời gian tồn tại có phạm vi.
  • Factory máy khách gRPC được định cấu hình để tạo các máy khách được đưa vào các dịch vụ gRPC và controller API Web.
  • Các lời gọi gRPC nên sử dụng ITokenProvider để nhận mã thông báo mang.
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}");
    }));

Đoạn code trên:

  • Định nghĩa ITokenProvider và AppTokenProvider. Những loại này xử lý việc phân giải mã thông báo xác thực cho các lời gọi gRPC.
  • Đăng ký loại AppTokenProvider với DI trong thời gian tồn tại trong phạm vi. AppTokenProvider lưu trữ mã thông báo để chỉ cần lời gọi đầu tiên trong phạm vi để tính toán nó.
  • Đăng ký loại GreeterClient với factory máy khách.
  • Cấu hình AddCallCredentials cho máy khách này. Delegate được thực thi mỗi khi lời gọi được thực hiện và thêm mã thông báo được trả về ITokenProvider vào siêu dữ liệu.

Xác thực chứng chỉ máy khách

Ngoài ra, máy khách có thể cung cấp chứng chỉ máy khách để xác thực. Xác thực chứng chỉ xảy ra ở cấp TLS, rất lâu trước khi nó được đưa vào ASP.NET Core. Khi yêu cầu vào ASP.NET Core, gói xác thực chứng chỉ máy khách cho phép bạn phân giải chứng chỉ thành file ClaimsPrincipal.

Ghi chú

Định cấu hình máy chủ để chấp nhận chứng chỉ máy khách. Để biết thông tin về việc chấp nhận chứng chỉ máy khách trong Kestrel, IIS và Azure, hãy xem Định cấu hình xác thực chứng chỉ trong ASP.NET Core.

Trong ứng dụng khách .NET gRPC, chứng chỉ ứng dụng khách được thêm vào HttpClientHandler sau đó được sử dụng để tạo ứng dụng khách 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);
}

Cơ chế xác thực khác

Nhiều cơ chế xác thực được hỗ trợ bởi ASP.NET Core hoạt động với gRPC:

  • ID nhập của Microsoft
  • Chứng chỉ khách hàng
  • Máy chủ nhận dạng
  • Mã thông báo JWT
  • OAuth 2.0
  • Kết nối OpenID
  • Liên đoàn WS

Để biết thêm thông tin về cách định cấu hình xác thực trên máy chủ, hãy xem xác thực ASP.NET Core.

Việc định cấu hình máy khách gRPC để sử dụng xác thực sẽ phụ thuộc vào cơ chế xác thực mà bạn đang sử dụng. Các ví dụ về mã thông báo mang và chứng chỉ ứng dụng khách trước đây cho thấy một số cách mà ứng dụng khách gRPC có thể được định cấu hình để gửi siêu dữ liệu xác thực bằng lệnh gọi gRPC:

  • Các máy khách gRPC được định kiểu mạnh sẽ sử dụng HttpClient nội bộ. Xác thực có thể được định cấu hình trên HttpClientHandler hoặc bằng cách thêm các thể hiện HttpMessageHandler tùy chỉnh vào HttpClient.
  • Mỗi lệnh gọi gRPC có một đối số CallOptions tùy chọn. Header tùy chỉnh có thể được gửi bằng collection header của tùy chọn.

Ghi chú

Không thể sử dụng Xác thực Windows (NTLM/Kerberos/Thương lượng) với gRPC. gRPC yêu cầu HTTP/2 và HTTP/2 không hỗ trợ Xác thực Windows.

Ủy quyền cho người dùng truy cập dịch vụ và phương thức dịch vụ

Theo mặc định, tất cả các phương thức trong một dịch vụ có thể được gọi bởi người dùng chưa được xác thực. Để yêu cầu xác thực, hãy áp dụng attribute [Authorize] cho dịch vụ:

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

Bạn có thể sử dụng các đối số và property hàm tạo của attribute [Authorize] để hạn chế quyền truy cập chỉ đối với những người dùng phù hợp với chính sách ủy quyền cụ thể. Ví dụ: nếu bạn có chính sách ủy quyền tùy chỉnh được gọi là MyAuthorizationPolicy, hãy đảm bảo rằng chỉ những người dùng phù hợp với chính sách đó mới có thể truy cập dịch vụ bằng đoạn code sau:

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

Các phương thức dịch vụ riêng lẻ cũng có thể được áp dụng attribute [Authorize]. Nếu người dùng hiện tại không khớp với các chính sách được áp dụng cho cả phương thứclớp, thì lỗi sẽ được trả về cho trình gọi:

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

Tài nguyên bổ sung

Nguồn: learn.microsoft.com
» Tiếp: Trình chặn gRPC trên .NET
« Trước: gRPC cho cấu hình .NET
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!