// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc { /// /// An authorization filter that confirms requests are received over HTTPS. /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class RequireHttpsAttribute : Attribute, IAuthorizationFilter, IOrderedFilter { /// public int Order { get; set; } /// /// Called early in the filter pipeline to confirm request is authorized. Confirms requests are received over /// HTTPS. Takes no action for HTTPS requests. Otherwise if it was a GET request, sets /// to a result which will redirect the client to the HTTPS /// version of the request URI. Otherwise, sets to a result /// which will set the status code to 403 (Forbidden). /// /// public virtual void OnAuthorization(AuthorizationFilterContext filterContext) { if (filterContext == null) { throw new ArgumentNullException(nameof(filterContext)); } if (!filterContext.HttpContext.Request.IsHttps) { HandleNonHttpsRequest(filterContext); } } /// /// Called from if the request is not received over HTTPS. Expectation is /// will not be null after this method returns. /// /// The to update. /// /// If it was a GET request, default implementation sets to a /// result which will redirect the client to the HTTPS version of the request URI. Otherwise, default /// implementation sets to a result which will set the status /// code to 403 (Forbidden). /// protected virtual void HandleNonHttpsRequest(AuthorizationFilterContext filterContext) { // only redirect for GET requests, otherwise the browser might not propagate the verb and request // body correctly. if (!string.Equals(filterContext.HttpContext.Request.Method, "GET", StringComparison.OrdinalIgnoreCase)) { filterContext.Result = new StatusCodeResult(StatusCodes.Status403Forbidden); } else { var optionsAccessor = filterContext.HttpContext.RequestServices.GetRequiredService>(); var request = filterContext.HttpContext.Request; var host = request.Host; if (optionsAccessor.Value.SslPort.HasValue && optionsAccessor.Value.SslPort > 0) { // a specific SSL port is specified host = new HostString(host.Host, optionsAccessor.Value.SslPort.Value); } else { // clear the port host = new HostString(host.Host); } var newUrl = string.Concat( "https://", host.ToUriComponent(), request.PathBase.ToUriComponent(), request.Path.ToUriComponent(), request.QueryString.ToUriComponent()); // redirect to HTTPS version of page filterContext.Result = new RedirectResult(newUrl, permanent: false); } } } }