3

特定の一連のアクションに対して SSL を必要とする MVC 4 Web アプリケーションがあり、ログイン プロセスも SSL で保護されるようにしたいと考えています。

すべてを設定した後、ログイン ページの redirectToUrl パラメータがスキーマを指定していないため、ログインが必要なすべてのページは、設定した (または設定しない[RequireHttps]ほうがよい) 属性に関係なく、https にリダイレクトされます。行動。

私が RequireHttps 属性で装飾していないページは混合コンテンツをホストしているため、これは通常のブラウザー警告を引き起こします。これはユーザーにとって混乱を招くため、避けたいと思います。

この問題を解決する方法はありますか? ログイン アクションからスキーマを取得することを考えましたが、単なる相対パスである returnUrl パラメーターを除いて、元の要求への参照が見つかりませんでした。

私が SO で見つけた参照は、https を必要としないすべてのアクションを装飾するためのカスタム属性を作成することですが、これ以上の DRY はありますか?

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 に答える