• AspNetCore3.1_Middleware源码解析_3_HttpsRedirection


    概述

    上文提到3.1版本默认没有使用Hsts,但是使用了这个中间件。看名字就很好理解,https跳转,顾名思义,就是跳转到
    https地址。

    使用场景,当用户使用http访问网站时,自动跳转到https地址。这样更加安全,不需要用户特意输入https://协议。

    具体做了些我们一起来看看。

      app.UseHttpsRedirection();
    

    使用方法

    跟Hsts一样,HttpsRedirection默认是不需要注入的,除非你需要修改默认配置。

    services.AddHttpsRedirection(config =>
      {
          //https地址的端口号,默认null
          config.HttpsPort = 12345;
    
          //跳转响应的状态码,默认307
          config.RedirectStatusCode = 302;
      });
    

    直接使用中间件即可

     app.UseHttpsRedirection();
    

    源码解析

    源代码很简单,只有两个类:HttpsRedirectionOptions配置类,HttpsRedirectionMiddleware中间件

    HttpsRedirectionOptions就只有两个配置项

      /// <summary>
      /// Options for the HttpsRedirection middleware
      /// </summary>
      public class HttpsRedirectionOptions
      {
          /// <summary>
          /// The status code used for the redirect response. The default is 307.
          /// </summary>
          public int RedirectStatusCode { get; set; } = StatusCodes.Status307TemporaryRedirect;
    
          /// <summary>
          /// The HTTPS port to be added to the redirected URL.
          /// </summary>
          /// <remarks>
          /// If the HttpsPort is not set, we will try to get the HttpsPort from the following:
          /// 1. HTTPS_PORT environment variable
          /// 2. IServerAddressesFeature
          /// If that fails then the middleware will log a warning and turn off.
          /// </remarks>
          public int? HttpsPort { get; set; }
      }
    

    重点看下中间件做了些什么。代码量很少,大体是这些逻辑。

    • 如果请求是Https,跳过本中间件
    • 中间件会依次尝试从这三个地方取端口号:HttpsRedirectionOptions的配置,HttpsRedirectionOptions,HTTPS_PORT环境变量或配置,IServerAddressesFeature(如果Webhost上绑定了https地址,本中间件能够解析出来端口号)。
    • 如果没有解析出来https的端口号,则跳过本中间件。
    • 如果能够解析出来https端口号,则拼接出来https地址,返回307跳转响应报文(或者配置的其他状态码)。

    注:3.1同时支持HTTPS_PORT和ANCM_HTTPS_PORT这两个环境变量。
    image

    https://docs.microsoft.com/en-us/dotnet/core/compatibility/2.2-3.0

    public class HttpsRedirectionMiddleware
        {
            private const int PortNotFound = -1;
    
            private readonly RequestDelegate _next;
            private readonly Lazy<int> _httpsPort;
            private readonly int _statusCode;
    
            private readonly IServerAddressesFeature _serverAddressesFeature;
            private readonly IConfiguration _config;
            private readonly ILogger _logger;
    
            /// <summary>
            /// Initializes the HttpsRedirectionMiddleware
            /// </summary>
            /// <param name="next"></param>
            /// <param name="options"></param>
            /// <param name="config"></param>
            /// <param name="loggerFactory"></param>
            public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, ILoggerFactory loggerFactory)
    
            {
                _next = next ?? throw new ArgumentNullException(nameof(next));
                _config = config ?? throw new ArgumentNullException(nameof(config));
    
                if (options == null)
                {
                    throw new ArgumentNullException(nameof(options));
                }
                var httpsRedirectionOptions = options.Value;
                if (httpsRedirectionOptions.HttpsPort.HasValue)
                {
                    _httpsPort = new Lazy<int>(() => httpsRedirectionOptions.HttpsPort.Value);
                }
                else
                {
                    _httpsPort = new Lazy<int>(TryGetHttpsPort);
                }
                _statusCode = httpsRedirectionOptions.RedirectStatusCode;
                _logger = loggerFactory.CreateLogger<HttpsRedirectionMiddleware>();
            }
    
            /// <summary>
            /// Initializes the HttpsRedirectionMiddleware
            /// </summary>
            /// <param name="next"></param>
            /// <param name="options"></param>
            /// <param name="config"></param>
            /// <param name="loggerFactory"></param>
            /// <param name="serverAddressesFeature">The</param>
            public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, ILoggerFactory loggerFactory,
                IServerAddressesFeature serverAddressesFeature)
                : this(next, options, config, loggerFactory)
            {
                _serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature));
            }
    
            /// <summary>
            /// Invokes the HttpsRedirectionMiddleware
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public Task Invoke(HttpContext context)
            {
                if (context.Request.IsHttps)
                {
                    return _next(context);
                }
    
                var port = _httpsPort.Value;
                if (port == PortNotFound)
                {
                    return _next(context);
                }
    
                var host = context.Request.Host;
                if (port != 443)
                {
                    host = new HostString(host.Host, port);
                }
                else
                {
                    host = new HostString(host.Host);
                }
    
                var request = context.Request;
                var redirectUrl = UriHelper.BuildAbsolute(
                    "https", 
                    host,
                    request.PathBase,
                    request.Path,
                    request.QueryString);
    
                context.Response.StatusCode = _statusCode;
                context.Response.Headers[HeaderNames.Location] = redirectUrl;
    
                _logger.RedirectingToHttps(redirectUrl);
    
                return Task.CompletedTask;
            }
    
            //  Returns PortNotFound (-1) if we were unable to determine the port.
            private int TryGetHttpsPort()
            {
                // The IServerAddressesFeature will not be ready until the middleware is Invoked,
                // Order for finding the HTTPS port:
                // 1. Set in the HttpsRedirectionOptions
                // 2. HTTPS_PORT environment variable
                // 3. IServerAddressesFeature
                // 4. Fail if not sets
    
                var nullablePort = _config.GetValue<int?>("HTTPS_PORT") ?? _config.GetValue<int?>("ANCM_HTTPS_PORT");
                if (nullablePort.HasValue)
                {
                    var port = nullablePort.Value;
                    _logger.PortLoadedFromConfig(port);
                    return port;
                }
    
                if (_serverAddressesFeature == null)
                {
                    _logger.FailedToDeterminePort();
                    return PortNotFound;
                }
    
                foreach (var address in _serverAddressesFeature.Addresses)
                {
                    var bindingAddress = BindingAddress.Parse(address);
                    if (bindingAddress.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
                    {
                        // If we find multiple different https ports specified, throw
                        if (nullablePort.HasValue && nullablePort != bindingAddress.Port)
                        {
                            _logger.FailedMultiplePorts();
                            return PortNotFound;
                        }
                        else
                        {
                            nullablePort = bindingAddress.Port;
                        }
                    }
                }
    
                if (nullablePort.HasValue)
                {
                    var port = nullablePort.Value;
                    _logger.PortFromServer(port);
                    return port;
                }
    
                _logger.FailedToDeterminePort();
                return PortNotFound;
            }
        }
    

    OK,完成了。

  • 相关阅读:
    Python学习杂记_2_格式化字符串的一些操作
    Python学习杂记_1_PyCharm使用的一些收获
    autolayout sizeclass 资料集锦
    据说这个是获得当前的控制器方法,没试过
    Mac下搭建php开发环境【转】
    搜索栏会消失 uisearchbar 狂点消失的问题解决
    mac下XAMPP服务器配置多站点配置局域网配置 (转)
    在 Xcode 6 中使用矢量图( iPhone 6 置配 UI)
    收到远程通知,怎么区分是点击通知栏提醒进去的还是在foreground收到的通知?
    开发经验之状态机思想,分别使用了swift,OC,C,PHP语言实现
  • 原文地址:https://www.cnblogs.com/holdengong/p/12505920.html
Copyright © 2020-2023  润新知