Как указать другой порт с атрибутом RequireHttps в MVC3 - PullRequest
8 голосов
/ 18 августа 2011

Я только изучаю ASP.NET MVC, и недавно я обнаружил атрибут [RequireHttps] для автоматического перенаправления запроса GET на использование SSL, например ...

[RequireHttps] //apply to all actions in controller
public class SomeController 
{
    [RequireHttps] //apply to this action only
    public ActionResult SomeAction()
    {
        ...
    }
}

При использовании IIS Express в качестве сервера разработки это успешно перенаправляет запрос с http://localhost:55945/... на https://localhost/....

Однако в моей системе разработки мой проект использует HTTPS на порту 44300 (это было автоматически настроено Visual Studio 2010), и я пока не нашел способа сказать MVC использовать этот номер порта в перенаправлении, чтобы вместо этого он идет к необходимому значению https://localhost:43300/....

Я действительно ожидал, что это будет автоматически, учитывая, что Visual Studio автоматически установил номер порта SSL, и, насколько я могу судить, это должно повлиять на всех разработчиков, использующих атрибут [RequireHttps] в MVC3. В своем поиске решения я видел несколько неоднозначных «обходных» решений, но ничего, что, казалось бы, не было «правильным способом» его исправить.

Таким образом, поступая «правильно», что я изменяю (либо в исходном коде, либо в конфигурации моего проекта), чтобы указать атрибуту [RequireHttps] в MVC3 использовать порт HTTPS, для которого настроен мой проект используя

Или, в качестве альтернативы, есть какой-то другой, совершенно иной и лучший «правильный» способ настройки поддержки SSL в проекте MVC3, у которого нет этой проблемы?

Ответы [ 4 ]

12 голосов
/ 18 августа 2011

RequireHttpsAttribute довольно прост и не может быть параметризован для перенаправления на определенный порт.Если вам это действительно нужно, вы можете создать подкласс и переопределить метод HandleNonHttpsRequest, чтобы составить URL перенаправления по-другому.

protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) {
    base.HandleNonHttpsRequest(filterContext);

    // redirect to HTTPS version of page
    string url = "https://" + filterContext.HttpContext.Request.Url.Host + ":" + MyConfig.SslPort + filterContext.HttpContext.Request.RawUrl;
    filterContext.Result = new RedirectResult(url);
}

Однако, если весь ваш сайт работает с HTTPS, вы можете просто настроить VS в свойствах веб-проекта (Web -> Start Action -> Start URL), чтобы открыть правильный URL HTTPS с вашим портом ине использовать функцию перенаправления для локального тестирования.

3 голосов
/ 25 сентября 2013

У меня такая же проблема, и я решаю ее, используя RequireHttpsAttribute и правило перезаписи URL в Web.config. Правило перезаписи соответствует номерам нестандартных портов и выполняется перед атрибутом. Вы можете использовать преобразование Web.config, чтобы удалить правило перезаписи при развертывании, но если вы его оставите, оно не должно иметь никакого эффекта. В производстве вы будете использовать стандартный номер порта, который не будет соответствовать правилу. Тогда атрибут его поймает.

Вот правило:

<system.webServer>
  <rewrite>
    <rules>
  <!-- Redirect HTTP requests to HTTPS, using the non-standard development ports.
  On deployment, this rule is removed, and the RequireHttpAttribute filter globally applied
  in SlicerWeb.FilterConfig takes over. This rewrite rule executes before the attribute
  would be applied, and so can apply the port numbers -->
      <rule name="HTTPS redirect" stopProcessing="true">
        <match url="(.*)" />
        <conditions>
          <add input="{HTTPS}" pattern="off" ignoreCase="true" />
          <add input="{SERVER_PORT}" pattern="60470" />
        </conditions>
        <action type="Redirect" url="https://{SERVER_NAME}:44300/{R:1}" redirectType="Found" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

Недостатком этого подхода является то, что вы не полагаетесь на атрибут при локальном запуске. Но если вы применили его один раз в глобальном масштабе, вместо того, чтобы добавлять его к каждому контроллеру, это нормально, на мой взгляд.

2 голосов
/ 15 января 2012

Несколько вещей, которые могут быть полезны.

В этом потоке есть версия исходного кода RequireHttpsAttribute: Где находится источник для RequireHttpsAttribute?

Существует также почти идентичный класс RequireSslAttribute в codeplex, упомянутый в том же потоке. http://aspnet.codeplex.com/SourceControl/changeset/view/63930#391756

Вот пример атрибута, который можно использовать для переключения с http на https или наоборот, на основе свойства TargetUriScheme. Он также включает свойства для указания номеров портов.

Я решил использовать блок #if DEBUG в своем конструкторе, чтобы установить свои локальные порты разработки при сборке в конфигурации Debug. Это работает для меня, поскольку при развертывании я всегда собираю версию под релиз, и в этом случае номера портов по умолчанию будут равны нулю и будут исключены из URL.

Номера портов также могут быть установлены при применении атрибута к методу действия. Я также мог бы увидеть их привязку к файлу конфигурации или другому источнику конфигурации для определения номеров портов во время выполнения.

public class ToggleHttpHttpsAttribute : FilterAttribute, IAuthorizationFilter
{
    //supported uri scheme values
    public enum UriScheme
    {
        Http,
        Https
    }

    public ToggleHttpHttpsAttribute(
        UriScheme uriScheme = UriScheme.Http)
    {
        TargetUriScheme = uriScheme;
    #if DEBUG
        //set DEBUG ports
        HttpPort = 55892;
        HttpsPort = 44301;
    #endif
    }

    private UriScheme TargetUriScheme { get; set; }
    public int? HttpPort { get; set; }
    public int? HttpsPort { get; set; }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if(filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        bool isHttps = filterContext.HttpContext.Request.IsSecureConnection;

        if ((isHttps && TargetUriScheme == UriScheme.Http) || (!isHttps && TargetUriScheme == UriScheme.Https))
        {
            ToggleUriScheme(filterContext);
        }
    }

    private void ToggleUriScheme(AuthorizationContext filterContext)
    {
        //only allow toggle if GET request
        if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET",   StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("ToggleHttpHttpsAttribute can only be used on GET requests.");
        }

        filterContext.Result = GetRedirectResult(filterContext);
    }

    private RedirectResult GetRedirectResult(AuthorizationContext filterContext)
    {
        string prefix = TargetUriScheme == UriScheme.Http
            ? "http://"
            : "https://";

        int? port = TargetUriScheme == UriScheme.Http
            ? HttpPort
            : HttpsPort;

        string url = string.Format(
            "{0}{1}{2}{3}",
            prefix,
            filterContext.HttpContext.Request.Url.Host,
            port == null ? "" : string.Format(":{0}", port),
            filterContext.HttpContext.Request.RawUrl);

        return new RedirectResult(url);
    }
}
0 голосов
/ 21 октября 2011

Я довольно озадачен тем, почему мне пришлось часами пытаться понять это правильно. Я сделал переписывание URL, подобное тому, как Скотт Хансельман объясняет это здесь:

http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx

Это прекрасно работает, и я просто убираю правило перезаписи на моем производственном веб-сервере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...