| File: Filters\AntiforgeryApplicationModelProvider.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.ViewFeatures\src\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj (Microsoft.AspNetCore.Mvc.ViewFeatures) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Linq; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc.Core.Filters; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.ApplicationModels; internal sealed class AntiforgeryApplicationModelProvider(IOptions<MvcOptions> mvcOptions, ILogger<AntiforgeryMiddlewareAuthorizationFilter> logger) : IApplicationModelProvider { private readonly MvcOptions _mvcOptions = mvcOptions.Value; private readonly AntiforgeryMiddlewareAuthorizationFilter AntiforgeryMiddlewareAuthorizationFilter = new(logger); public int Order => -1000 + 10; public void OnProvidersExecuting(ApplicationModelProviderContext context) { ArgumentNullException.ThrowIfNull(context); if (!_mvcOptions.EnableEndpointRouting) { return; } foreach (var controllerModel in context.Result.Controllers) { var controllerFilterAdded = false; if (HasValidAntiforgeryMetadata(controllerModel.Attributes, controllerModel.Filters)) { controllerModel.Filters.Add(AntiforgeryMiddlewareAuthorizationFilter); controllerFilterAdded = true; } // Connect [IgnoreAntiforgeryToken] applied to the controller into endpoint metadata. if (controllerModel.Attributes.OfType<IgnoreAntiforgeryTokenAttribute>().Any()) { foreach (var selector in controllerModel.Selectors) { selector.EndpointMetadata.Add(AntiforgeryMetadata.ValidationNotRequired); } } foreach (var actionModel in controllerModel.Actions) { if (HasValidAntiforgeryMetadata(actionModel.Attributes, actionModel.Filters) && !controllerFilterAdded) { actionModel.Filters.Add(AntiforgeryMiddlewareAuthorizationFilter); } // Connect [IgnoreAntiforgeryToken] on an action to the endpoint metadata. if (actionModel.Attributes.OfType<IgnoreAntiforgeryTokenAttribute>().Any()) { foreach (var selector in actionModel.Selectors) { selector.EndpointMetadata.Add(AntiforgeryMetadata.ValidationNotRequired); } } } } } public void OnProvidersExecuted(ApplicationModelProviderContext context) { // Intentionally empty. } private static bool HasValidAntiforgeryMetadata(IReadOnlyList<object> attributes, IList<IFilterMetadata> filters) { var antiforgeryMetadata = attributes.OfType<IAntiforgeryMetadata>(); var antiforgeryAttribute = filters.OfType<ValidateAntiForgeryTokenAttribute>().FirstOrDefault(); if (antiforgeryAttribute is not null && antiforgeryMetadata.Any()) { throw new InvalidOperationException($"Cannot apply [{nameof(ValidateAntiForgeryTokenAttribute)}] and [{nameof(RequireAntiforgeryTokenAttribute)}] at the same time."); } return antiforgeryMetadata.Any(); } }