Есть ли способ добавить метаданные ко всем конечным точкам GET в ASP.NET Core?

В следующем операторе добавляется атрибут ко всем конечным точкам. Затем есть промежуточное ПО, которое специально ищет этот атрибут и, если он присутствует, проверяет наличие заголовка защиты от подделки.

endpoints.MapControllers().RequireAuthorization().AsBffApiEndpoint();

Мне нужно иметь возможность обойти эту проверку на всех конечных точках GET. Самое главное, что это сторонняя библиотека, поэтому я не могу контролировать ее реализацию.

Я пробовал много вещей без успеха. Последней попыткой было добавить пользовательское промежуточное ПО промежуточного слоя. app.Use(...)и если атрибут присутствовал, то удалить его. Однако это невозможно, поскольку список метаданных readonly. Тогда моя последняя надежда - найти способ добавить один и тот же атрибут - ко всем GET- с флагом falseкоторый игнорирует проверку. Другими словами, все AsBffApiEndpoint()украшает конечную точку [BffApi]атрибут. Этот атрибут игнорирует заголовки защиты от форери, если используется таким образом. Я знаю, что решение хакерское, потому что в итоге я получу что-то вроде этого.

      [BffApi]
[BffApi(false)]
//endpoint definition here

Хорошей новостью является то, что они получают упорядоченные метаданные конечной точки. endpoint.Metadata.GetOrderedMetadata<BffApiAttribute>(). Значение до тех пор, пока [BffApi(false)]имеет приоритет в списке, я должен быть хорошим.

1 ответ

Я нашел решение и не добавлял второй атрибут, а скорее расширял конструктор. Таким образом, я мог изменить метаданные конечных точек, которые в этот момент могут быть изменены.

      public static TBuilder AsBffApiEndpointBypassAntiforgeryOnGET<TBuilder>(this TBuilder builder, string routePrefix) where TBuilder : IEndpointConventionBuilder
{
    builder.Add(endpointBuilder =>
    {
        var getAttribute = endpointBuilder.Metadata.FirstOrDefault(m => m.GetType() == typeof(HttpGetAttribute)) as HttpGetAttribute;
        var routeAttribute = endpointBuilder.Metadata.FirstOrDefault(m => m.GetType() == typeof(RouteAttribute)) as RouteAttribute;
        if (getAttribute != null && routeAttribute != null && routeAttribute.Template.StartsWith(routePrefix))
        {
            endpointBuilder.Metadata.Add(new BffApiAttribute(false));
        }
        else
        {
            endpointBuilder.Metadata.Add(new BffApiAttribute(true));
        }
    });

    return builder;
}

Затем в

          app.UseEndpoints(endpoints =>
    {
        endpoints.MapBffManagementEndpoints();
        endpoints.MapControllers().RequireAuthorization().AsBffApiEndpointBypassAntiforgeryOnGET("api/Foo");
    });

Более общая реализация будет следующей.

      public static IEndpointConventionBuilder AddConditionalMetadata(this IEndpointConventionBuilder builder, Func<EndpointBuilder, bool> evalEndpoint, Action<EndpointBuilder> onEvalTrue, Action<EndpointBuilder> onEvalFalse)
{
    builder.Add(endpointBuilder =>
    {
        if (evalEndpoint.Invoke(endpointBuilder))
        {
            onEvalTrue.Invoke(endpointBuilder);
        }
        else
        {
            onEvalFalse.Invoke(endpointBuilder);
        }
    });

    return builder;
}

Таким образом вы предоставляете функцию для оценки и действия для выполнения. Тогда ваш Startup.csизменится на это.

      app.UseEndpoints(endpoints =>
{
    endpoints.MapBffManagementEndpoints();
    endpoints.MapControllers().RequireAuthorization().AddConditionalMetadata(
        evalEndpoint: (endpointBuilder) => 
        {
            var routeAttribute = endpointBuilder.Metadata.FirstOrDefault(m => m.GetType() == typeof(RouteAttribute)) as RouteAttribute;
            var getAttribute = endpointBuilder.Metadata.FirstOrDefault(m => m.GetType() == typeof(HttpGetAttribute)) as HttpGetAttribute;
            return getAttribute != null && routeAttribute != null && routeAttribute.Template.StartsWith("api/Foo");
        }, 
        onEvalTrue: (endpointBuilder) => { endpointBuilder.Metadata.Add(new BffApiAttribute(false)); },
        onEvalFalse: (endpointBuilder) => { endpointBuilder.Metadata.Add(new BffApiAttribute()); });
});

Я надеюсь, что это может помочь кому-то еще, кто ищет то же самое.

Другие вопросы по тегам