Duende BFF Yarn не передает токены при использовании веб-клиента gRpc из приложения Blazor WebAssembly
Я создаю веб-приложение с ASP.NET Core 6.
У меня есть:
- Frontend.Client — Blazor WebAssembly с пользовательским интерфейсом
- Frontend.Server — ASP.NET Core, на котором размещается Blazor WebAssembly.
- Web Api — удаленная служба REST
- Служба gRpc — удаленная служба gRpc.
- Identity Provider — проект Duende с использованием Duende.Bff.Yarp.
Мой Frontend.Client настроен на вызов собственного BFF (Frontend.Server), в то время как сервер перенаправляет вызовы на службы REST и gRpc с помощью Duende.Bff.YARP .
Вызовы службы REST работают как положено: клиент передает токен автоматически, как по документации.
Моя проблема связана с вызовами gRpc, которые, похоже, не используют правильный HttpClient с AntiForgeryToken и токеном доступа, как следует.
Я знаю, что где-то пропустил некоторые настройки, но я не могу найти ни одного примера того, как использовать Duende с gRpcWebClient.
Моя конфигурация Frontend.Client содержит:
builder.Services.AddScoped<AuthenticationStateProvider, BffAuthenticationStateProvider>();
builder.Services.AddTransient<AntiforgeryHandler>();
builder.Services.AddHttpClient("backend", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<AntiforgeryHandler>();
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("backend"));
builder.Services.AddSingleton(services => {
var backendUrl = new Uri(builder.HostEnvironment.BaseAddress);
var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions {
HttpHandler = new GrpcWebHandler(new HttpClientHandler()),
});
return new Commenter.CommenterClient(channel);
});
Моя конфигурация Frontend.Server содержит:
builder.Services.AddBff();
var proxyBuilder = builder.Services.AddReverseProxy().AddTransforms<AccessTokenTransformProvider>();
// Initialize the reverse proxy from the "ReverseProxy" section of configuration
proxyBuilder.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
builder.Services.AddAuthentication(options => {
options.DefaultScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
options.DefaultSignOutScheme = "oidc";
})
.AddCookie("cookie", options => {
options.Cookie.Name = "__Host-blazor";
options.Cookie.SameSite = SameSiteMode.Strict;
})
.AddOpenIdConnect("oidc", options => {
options.Authority = "https://localhost:5007";
options.ClientId = "photosharing.bff";
options.ClientSecret = "A9B27D26-E71C-4C53-89A8-3DAB53CE1854";
options.ResponseType = "code";
options.ResponseMode = "query";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("photosrest");
options.Scope.Add("commentsgrpc");
options.Scope.Add("offline_access");
options.MapInboundClaims = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
//code omitted for brevity
app.UseAuthentication();
app.UseBff();
app.UseAuthorization();
app.MapBffManagementEndpoints();
app.MapReverseProxy().AsBffApiEndpoint();
Файл appsettings.json, используемый для чтения конфигурации, содержит:
"ReverseProxy": {
"Routes": {
"photosrestroute": {
"ClusterId": "photosrestcluster",
"Match": {
"Path": "/photos/{*any}"
},
"Metadata": {
"Duende.Bff.Yarp.TokenType": "User"
}
},
"commentsgrpcroute": {
"ClusterId": "commentsgrpccluster",
"Match": {
"Path": "/comments.Commenter/{*any}"
},
"Metadata": {
"Duende.Bff.Yarp.TokenType": "User"
}
}
},
"Clusters": {
"photosrestcluster": {
"Destinations": {
"photosrestdestination": {
"Address": "https://localhost:5003/"
}
}
},
"commentsgrpccluster": {
"Destinations": {
"commentsgrpdestination": {
"Address": "https://localhost:5005/"
}
}
}
}
}
Когда мой клиент вызывает gRpc, я получаю ответ 401 Unauthorized и Duende.Bff регистрирует, что проверка AntiForgery не прошла, на самом деле запрос не имеет заголовка с X-CSRF 1 (в то время как вызовы REST Api делают ). Это предполагает, что клиент gRpc не использует HTTP-клиент, который использует Дуэнде.
Как подключить мой клиент gRpc к Duende?
ПРИМЕЧАНИЕ: до введения бита аутентификации/авторизации я использовал YARP напрямую, и вызовы gRpc работали нормально. Когда я добавил Дуэнде, он сломался.
1 ответ
Проблема заключалась в AntiforgeryHandler, так как я не добавил его в цепочку HttpHandlers моего gRpcChannel. Что я сделал, чтобы решить это, было
- Добавьте конструктор в мой AntiforgeryHandler, чтобы принять внутренний обработчик и передать его базовому классу.
- Прикрепите мой AntiforgeryHandler к цепочке HttpHandler, управляющей построением клиента grpc.
AntiforgeryHandler становится:
namespace PhotoSharingApplication.Frontend.Client.DuendeAuth;
public class AntiforgeryHandler : DelegatingHandler {
public AntiforgeryHandler() { }
public AntiforgeryHandler(HttpClientHandler innerHandler) : base(innerHandler) { }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
request.Headers.Add("X-CSRF", "1");
return base.SendAsync(request, cancellationToken);
}
}
Конструкция клиента grpc в моем проекте Frontend.Client выглядит следующим образом:
builder.Services.AddSingleton(services => {
var backendUrl = new Uri(builder.HostEnvironment.BaseAddress);
var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions {
HttpHandler = new GrpcWebHandler(new AntiforgeryHandler(new HttpClientHandler())),
});
return new Commenter.CommenterClient(channel);
});