netcore 解决 内网Http 的301 ,302跳转引起的https降级到http无法显示页面的问题

10/12/2022 11:13:52 AM
609
0

内网多个服务,使用的是http

域名请求经过https 协议请求到网关,网关使用http转发到内网服务。

内网获取到的协议头自然是http的,但是经过网关后header中带有了原始请求的协议头,存储在 X-Forwarded-Proto  中。

当内网要验证权限时候,有可能涉及到301,302的跳转。本次解决的问题,通过授权的跳转前事件 进行解决的,如果读者感兴趣可以通过中间件来解决

首先,在注册cookie票据认证时候需要配置上事件的处理程序

.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                options.Cookie.Name = "xxxx";
                options.LoginPath = "/account/login";   //默认此路径,可以使用自定义路径
                options.AccessDeniedPath = "/account/accessDenied";
                options.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, options.Events.OnRedirectToAccessDenied);   //注册跳转到未授权页面前的执行程序
                options.Events.OnRedirectToLogin = ReplaceRedirector(HttpStatusCode.Unauthorized, options.Events.OnRedirectToLogin);   //注册跳转到登录页面 前 的执行程序
            });

  //设置ajax下对状态码的处理逻辑,避免401  403这样的状态会返回302状态码
  services.ConfigureApplicationCookie(options =>
            {
                options.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, options.Events.OnRedirectToAccessDenied);
                options.Events.OnRedirectToLogin = ReplaceRedirector(HttpStatusCode.Unauthorized, options.Events.OnRedirectToLogin);
            });

 

执行程序中对响应的状态码,跳转地址等做处理。 本程序自动检测原始请求是https的时候,将内网的301/302 跳转地址转为  https头,这样就要不会出现协议降级的问题

   //程序方法替换重定向方法
        Func<RedirectContext<CookieAuthenticationOptions>, Task> ReplaceRedirector(HttpStatusCode statusCode, Func<RedirectContext<CookieAuthenticationOptions>, Task> existingRedirector)
        {
            Func<RedirectContext<CookieAuthenticationOptions>, Task> abc = (context) =>
            {
                Console.WriteLine("授权认证失败");
                if (context.Request.Headers.ContainsKey("X-Requested-With") && context.Request.Headers["x-Requested-With"] == "XMLHttpRequest")
                {
                    context.Response.StatusCode = (int)statusCode;
                    return Task.CompletedTask;
                }

                string reqScheme = Utils.Core.RequestHelper.GetScheme();
                Console.WriteLine("认证请求的协议:" + reqScheme);
                
                if (reqScheme == "https" && !context.RedirectUri.StartsWith("https"))
                {
                    //检测并替换Response 
                    context.Response.StatusCode = 301;
                    context.RedirectUri = "https" + context.RedirectUri.Remove(0, 4);
                    //return Task.CompletedTask;
                }


                return existingRedirector(context);
            };
            return abc;
        }

 

附上检测协议头的方法:

  public static  string  GetScheme()
        {
            string   schemes = HttpContextUtil.Current.Request.Headers["X-Forwarded-Proto"].FirstOrDefault();   
            if (string.IsNullOrWhiteSpace(schemes))
            {
                return HttpContextUtil.Current.Request.Scheme;
            }
            string[]  s=schemes.Split(',',StringSplitOptions.RemoveEmptyEntries);
            return s[0];
        }

 HttpContextUtil.Current.Request  就是 http请求的 Request ,读者想办法自行获取到就可以替换这里的 Request对象

全部评论



提问