3

我有一个 MVC 4 Web 应用程序,我需要 SSL 来执行一组特定的操作,现在我希望登录过程也受 SSL 保护。

设置完所有内容后,由于登录页面的 redirectToUrl 参数未指定架构,所有需要登录的页面都会重定向到 https,无论[RequireHttps]我在行动。

由于我没有用 RequireHttps 属性修饰的页面托管混合内容,这会触发通常的浏览器警告,这会让用户感到困惑,我想避免。

有没有办法解决这个问题?我想从登录操作中获取架构,但是除了 returnUrl 参数(它只是一个相对路径)之外,我找不到对原始请求的引用。

我在 SO 中找到的参考是创建一个自定义属性来装饰每个不需要 https 的操作,但是还有什么比这更干燥的吗?

4

2 回答 2

2

我发现以下内容很有用,而不是使用 [RequireHttps] 进行装饰,而是使用 [Secure] 进行装饰,然后此属性为我工作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MyNameSpace.Attributes
{
    public class SecureAttribute : ActionFilterAttribute
    {
        #region Variables and Properties
        public bool PermanentRedirect { get; set; }
        #endregion

        #region Public Methods
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Cache for efficiency
            var request = filterContext.HttpContext.Request;
            var response = filterContext.HttpContext.Response;

            // Make sure we're not in https or local
            if (!request.IsSecureConnection)
            {
                string redirectUrl = request.Url.ToString().Replace(
                    Uri.UriSchemeHttp,
                    Uri.UriSchemeHttps);

                if (PermanentRedirect)
                {
                    // Set the status code and text description to redirect permanently
                    response.StatusCode = 301;
                    response.StatusDescription = "Moved Permanently";
                }
                else
                {
                    // Set the status code and text description to redirect temporary (found)
                    response.StatusCode = 302;
                    response.StatusDescription = "Found";
                }

                // Add the location header to do the redirect
                response.AddHeader("Location", redirectUrl);
            }

            base.OnActionExecuting(filterContext);
        }
        #endregion
    }
}
于 2012-05-27T09:35:25.057 回答
2

好吧,我最终选择了我原始帖子评论中描述的解决方案,这被证明是最轻松的方法。

总结一下(代码的所有功劳归功于Luke Sampsons,我只是在这里重新发布以供快速参考)这基本上是代码:

public class ExitHttpsIfNotRequiredAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            // abort if it's not a secure connection
            if (!filterContext.HttpContext.Request.IsSecureConnection) return;

            // abort if a [RequireHttps] attribute is applied to controller or action
            if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Length > 0) return;
            if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Length > 0) return;

            // abort if a [RetainHttps] attribute is applied to controller or action
            if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RetainHttpsAttribute), true).Length > 0) return;
            if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(RetainHttpsAttribute), true).Length > 0) return;

            // abort if it's not a GET request - we don't want to be redirecting on a form post
            if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) return;

            // redirect to HTTP
            string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url);
        }
    }
    public  class RetainHttpsAttribute:FilterAttribute{}

ExitHttpsIfNotRequired属性可用于装饰用于派生 Web 应用程序中所有控制器的基本控制器类。

于 2012-05-31T18:25:42.113 回答