Идентификатор входа в систему ASP.Net для переадресации протокола (Https)

Надеюсь, я просто пропустил что-то действительно простое/очевидное - почему, и что более важно, как вы поддерживаете (или усиливаете) протокол во время перенаправления на Login?

Чтобы проиллюстрировать:

request trace

  • исходный протокол https
  • можно подумать, что это должно быть "по умолчанию" для чего-то вроде Login, но, как показано, перенаправление (кажется) не поддерживает его.

Материал, который я пробовал:

  • Существует атрибут RequireHttps, который можно использовать, но:

    • кажется "странным", что для получения "там" потребуется 2 переадресации
    • в ситуациях, когда у вас есть балансировщик нагрузки и/или выгружаете SSL в другом месте (а не на сервере), тогда это будет цикл переадресации (SSL между клиентом и интерфейсом net/ssl lb и http к вашему ящику/приложению). Это на самом деле мой производственный случай...
  • Я уже переписал URL-адрес URL-адреса IIS (aka canonical) для https для всего сайта), , и это кажется "проигнорированным" (тоже) (правило не проверяет "https", иначе оно будет иметь такой же цикл переадресации).

  • попробовал и не смог установить абсолютный URL-адрес в LoginPathCookieAuthenticationOptions).. потому что вы не можете этого сделать...

Спасибо за советы или указатели...


Update

Что касается "почему" ?

  1. в ситуациях, когда у вас есть балансировщик нагрузки и/или выгружаете SSL в другом месте (а не на сервере), тогда это будет цикл переадресации (SSL находится между клиентом и интерфейсом net/ssl lb и http к вашему ящику/приложению). Это на самом деле мое производство случай..

Дальнейшее вмешательство привело меня к вышесказанному, как показано в этой последовательности (localhost - мой локальный dev, а не сервер) (указанная выше проблема проявляется в балансированной рабочей нагрузке среде, где обработка SSL "вверх по стеку" - например ARR):

localhost https

  • протокол фактически поддерживается
  • проблема кажется ровно, связанной с ситуацией, когда приложение и "инфраструктура" не соответствуют друг другу. Похоже на ситуацию, когда в коде вы делаете Request.IsSecureConnection в среде с балансировкой нагрузки/веб-фермы (например, скажем ARR, где cert находится в вашем ARR, а не в вашем хосте /s ). Эта проверка всегда будет возвращать false в такой ситуации.

Итак, вопрос действительно в руководстве , как, чтобы обойти это?


Обновление 2

Большое спасибо Ричарду за то, что он изменил мое "направление", пытаясь решить это. Я изначально искал способ:

  • установить/сообщить OWIN/Identity использовать безопасный URL (явно) и "переопределить" способ оценки LoginPath. Опция Secure (only) при обработке файлов cookie каким-то образом привела меня таким образом (если я могу явно указывать файлы cookie только в HTTPS, то это вроде как дало мне представление о возможности сделать это для LoginPath.. в один конец или другой)

  • "Хакерный" способ в моей голове состоял в том, чтобы просто обработать его на стороне клиента (Javascript).

В конце концов, Ричард ответ взял меня на URL Rewriting (хотя все еще не на стороне LB, потому что это не под моим контролем). В настоящее время я работаю (на основе моей среды):

<rule name="Redirect to HTTPS" stopProcessing="true">
    <match url=".*" />

    <conditions>
      <add input="{HTTP_CLUSTER_HTTPS}" pattern="^on$" negate="true" />
      <add input="{HTTP_CLUSTER_HTTPS}" pattern=".+" negate="true" />

    </conditions>
    <action type="Redirect" url="https://{HTTP_HOST}{SCRIPT_NAME}/{REQUEST_URI}" redirectType="SeeOther" />
</rule>

и увидеть некоторый свет в конце туннеля.


Обновление 3

Удивительная благодарность Ричарду за слежку! Последний ответ заставил меня тоже замолчать, и там оказалось довольно несколько сообщений здесь, на SO, связанных с CookieApplyRedirectContext... так что теперь это то, что у меня на месте (что характерно для моего случая), и это то, что я изначально собирался после:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
   AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
   LoginPath = new PathString("/Account/Login"),

   //This is why. If I could explicitly set this, then I (thought) I should
   //be able to explicitly enforce https (too..as a setting)
   //for the LoginPath...
   CookieSecure = CookieSecureOption.Always,

   Provider = new CookieAuthenticationProvider 
   {
      OnValidateIdentity = .....
      ,
      OnApplyRedirect = context =>
      {
         Uri absoluteUri;
          if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out absoluteUri))
          {
             var path = PathString.FromUriComponent(absoluteUri);
             if (path == context.OwinContext.Request.PathBase + context.Options.LoginPath)
             {
                context.RedirectUri = context.RedirectUri.Replace("http:", "https:");
             }
           }
          context.Response.Redirect(context.RedirectUri);
        }
     }
});

Ответ 1

Эта проблема возникает, потому что ваше приложение отправляет перенаправление на абсолютный URL-адрес. Вы можете исправить это одним из двух способов: в балансировщике нагрузки или в самом приложении.

Балансировщик нагрузки

Настройте балансировщик нагрузки, чтобы переписать ответы перенаправления с http на https. Если вы использовали ARR, следующее правило (взятое из здесь) должно работать:

<rule name="forum-redirect" preCondition="IsRedirection" enabled="true">
  <match serverVariable="RESPONSE_LOCATION" pattern="^http://[^/]+/(.*)" />
  <conditions>
    <add input="{ORIGINAL_HOST}" pattern=".+" />
  </conditions>
  <action type="Rewrite" value="http://{ORIGINAL_HOST}/{R:1}" />
</rule>

Другие балансировки нагрузки потребуют аналогичной конфигурации.

Применение

Мы можем заменить URL-адрес, который OWIN перенаправляет в процессе авторизации с относительным URL-адресом, что означает, что протокол останется таким, каким ранее пользовался браузер.

В источнике Owin потребовалось немного копания, чтобы найти, как это сделать, но следующее изменение для запуска приложения должно решить ваши проблемы. Сначала извлеките инициализацию CookieAuthenticationProvider из конфигурации запуска.

Изменить:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider 
    {
        // Move these options in the step below...
    }
});

To:

var cookieProvider = new CookieAuthenticationProvider
{ 
    // ... Options from your existing application
};
// Modify redirect behaviour to convert login URL to relative
var applyRedirect = cookieProvider.OnApplyRedirect;
cookieProvider.OnApplyRedirect = context =>
{
    if (context.RedirectUri.StartsWith("http://" + context.Request.Host))
    {
        context.RedirectUri = context.RedirectUri.Substring(
            context.RedirectUri.IndexOf('/', "http://".Length));
    }
    applyRedirect(context);
};

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = cookieProvider
});

Пока мы не можем получить доступ к правилу перенаправления, OWIN использует делегат для выполнения фактического перенаправления. То, что я здесь сделал, это сохранить делегат, изменить URL-адрес, который он должен будет предоставить, а затем снова вызвать его.

С помощью этой опции убедитесь, что любые другие перенаправления и ссылки на вашем сайте относительны.

Ответ 2

Это небольшая модификация опции "Приложение" в Ответ Ричарда. Некоторые из манипуляций с строками делегируются в класс Uri.

var cookieProvider = new CookieAuthenticationProvider
{ 
    // ... Options from your existing application
};
// Modify redirect behaviour to convert login URL to relative
var applyRedirect = cookieProvider.OnApplyRedirect;
cookieProvider.OnApplyRedirect = context =>
{
    var redirectUri = new Uri(context.RedirectUri, UriKind.Absolute);

    if (redirectUri.Scheme == "http" && redirectUri.Host == context.Request.Uri.Host)
    {
        context.RedirectUri = redirectUri.PathAndQuery;
    }

    applyRedirect(context);
};

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = cookieProvider
});