Перемещение между HTTP и HTTPS в ASP.NET MVC - PullRequest
8 голосов
/ 25 ноября 2010

Итак, я обнаружил атрибут [requireHttps], но как только вы зашли в https, вы там застряли, поэтому, чтобы попытаться выполнить действия с одним URL (и схемой), я обнаружил, что в итоге необходимость создания собственного ExtendedController для возврата обратно на http для действий, которые не используют [RequireHttps].

Просто интересно, хорошо ли то, что я делаю, или есть лучший способ?

public class ExtendedController : Controller
{
    protected virtual void HandleHttpRequest(AuthorizationContext filterContext)
    {
        if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Cannot post between https and http.");
        }
        string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
        filterContext.Result = new RedirectResult(url);
    }

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
        if (!attributes.Any(a => a is RequireHttpsAttribute))
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            if (filterContext.HttpContext.Request.IsSecureConnection)
            {
                this.HandleHttpRequest(filterContext);
            }
        }
    }
}

Ответы [ 2 ]

11 голосов
/ 23 декабря 2010

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

public class RequireHttpsAttribute : System.Web.Mvc.RequireHttpsAttribute
{
    public bool RequireSecure = false;

    public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)

    {
        if (RequireSecure)
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
            // non secure requested
            if (filterContext.HttpContext.Request.IsSecureConnection)
            {
                HandleNonHttpRequest(filterContext);
            }
        }
    }

    protected virtual void HandleNonHttpRequest(AuthorizationContext filterContext)
    {
        if (String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            // redirect to HTTP version of page
            string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url);
        }
    } 
}

Затем на вашемМетод действия или контроллер, который вы бы использовали:

[RequireHttps (RequireSecure = true)]

...

или

[RequireHttps (RequireSecure = false)]
1 голос
/ 17 января 2012

Чтобы сделать его немного более управляемым. Это решение предполагает, что большинство ваших веб-приложений используют схему HTTP .

  1. Создание нового фильтра действий требует Http (используйте HTTP, если атрибут NeedSsl явно не применяется к действию или контроллеру),

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase req = filterContext.HttpContext.Request;
        HttpResponseBase res = filterContext.HttpContext.Response;
    
        bool needSsl = filterContext.ActionDescriptor.IsDefined(typeof(NeedSslAttribute), true)
                        || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(NeedSslAttribute), true);
    
    
        if (needSsl && !req.IsSecureConnection) //https: secure
        {
            var builder = new UriBuilder(req.Url)
            {
                Scheme = Uri.UriSchemeHttps,
                Port = 444
            };
            res.Redirect(builder.Uri.ToString());
        }
        else if (!needSsl && req.IsSecureConnection) //http: non secure
        {
            var builder = new UriBuilder(req.Url)
            {
                Scheme = Uri.UriSchemeHttp,
                Port = 8081
            };
            res.Redirect(builder.Uri.ToString());
        }
        base.OnActionExecuting(filterContext);
    }
    
  2. И новый пустой атрибут NeedSSL (для целей индикации)

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class NeedSslAttribute : Attribute { }
    
  3. Применить requireHttp в качестве фильтра глобальных действий в Global.aspx.cs

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new RequiresHttp());
    }
    
  4. Теперь примените применение NeedSslAttribute на контроллерах и действиях, где вы хотите использовать схему HTTPS

    [NeedSsl]
    [AllowAnonymous]
    public ActionResult LogOn()
    

Этот код не идеален, так как фильтр действий RequiresHttp выполняет несколько заданий, то есть проверяет атрибут NeedSsl и применяет схему HTTP или HTTPS. Было бы лучше, если бы мы могли использовать два фильтра действий RequiresHTTP и RequiresHTTPS.

Теперь, если RequiresHTTP был установлен как глобальный фильтр, и RequiresHTTPS фильтр был применен к определенным действиям, и конкретный RequiresHTTPS фильтр имел бы преимущество.

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