Ryan
Ryan

Reputation: 291

.NETCore Middleware Redirect Removing Path IIS Sub Application

I have a middleware class that reads the user's cookies and validates them, then redirects to a login URL if they are invalid or missing. The URL that the user is redirected to contains a 'back' parameter. This middleware works perfectly fine on a static-file SPA and when the application is not a nested application within IIS.

My Question, this does not work when using MVC controllers and Views, before the user is redirected to the login page somehow the path (which points to the nested IIS site) is stripped and the back URL does not contain the URL path. Any ideas?

What happens

Go to -> http://test.com/mysite

Redirects to -> http://login.com?back=http://test.com

What should happen

Go to -> http://test.com/mysite

Redirects to -> http://login.com?back=http://test.com/mysite

public class MyMiddleware
  {

    private readonly RequestDelegate _next;

    private readonly ILogger _logger;

    private readonly IOptions<MyMiddlewareOptions> _options;


    public MyMiddleware(RequestDelegate next, IOptions<MyMiddlewareOptions> options, ILoggerFactory logger)
    {
      _next    = next;
      _options = options;
      _logger = logger.CreateLogger("My Middleware");
    }


      public async Task Invoke(HttpContext context)
    {
      var middlewareCookieValidator = context.RequestServices.GetService<IMiddlewareCookieValidator>();

      await new CookieRequestCultureProvider().DetermineProviderCultureResult(context);

      if (!_options.Value.Bypass && !Path.HasExtension(context.Request.Path.Value))
      {
        try
        {
            if (wslCookieValidator.HasCreatedCookies(context) || await middlewareCookieValidator.ValidateCookiesAsync())
            {
              context.Response.OnStarting(async () => await middlewareCookieValidator.GenerateAndApplyCookiesToResponse(context));

              await _next(context);
            }
            else
            {
              var location = new Uri($"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}");

              context.Response.Redirect($"{_options.Value.Url}?back={location}");
            }

        }
        catch (Exception exception)
        {
          throw new Exception($"RequestDelegate '_next' = {_next}.  {exception.Message}");
        }
      }
      else
      {
        await _next(context);
      }
    }

  }

}

Upvotes: 0

Views: 779

Answers (2)

Ryan
Ryan

Reputation: 291

@Lex Li

Thank you for your answer, turns out due to IIS running with sub-applications.

I needed the following for it to work.

var location = new Uri($"{context.Request.Scheme}://{context.Request.Host}{context.Request.PathBase}{context.Request.Path}{context.Request.QueryString}");

Upvotes: 0

Henk Mollema
Henk Mollema

Reputation: 46541

This might be an URL encoding issue. You should encode the URL you pass into the back query-string parameter using System.Net.WebUtility.UrlEncode(). For example:

using System.Net;

// ...

var location = new Uri($"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}");

context.Response.Redirect($"{_options.Value.Url}?back={WebUtility.UrlEncode(location)}");

Upvotes: 1

Related Questions