【问题标题】:Set ValidateAntiForgeryToken attribute to GET/POST for same action MVC5将 ValidateAntiForgeryToken 属性设置为 GET/POST 以获得相同的操作 MVC5
【发布时间】:2016-04-02 16:39:57
【问题描述】:

我的问题很直接......

我有一个Action,它同时接受HttpGetHttpPost,但我想在http 请求为POST 时为操作设置ValidateAntiForgeryToken 属性,而不是HttpGet

我可以在action里面找到请求是GET还是POST,但是在调用action之前我需要知道。

    [ValidateAntiForgeryToken]  // Only for HttpPost
    public ActionResult Index() // Allows HttpPost / HttpGet
    {

    }

有没有可能在不重复操作的情况下实现这一点?

谢谢

【问题讨论】:

    标签: c# asp.net-mvc-5 antiforgerytoken


    【解决方案1】:

    您可以有条件地检查请求的 HTTP 方法并自己手动进行验证:

    if (Request.Method.ToLower() == "post") 
    {
        System.Web.Helpers.AntiForgery.Validate();
    }
    

    【讨论】:

    • 有效,但使用 if (Request.HttpMethod == WebRequestMethods.Http.Post) 代替 if 语句,因为控制器中不存在 Request.Method
    【解决方案2】:

    首先,这是一个非常糟糕的设计。 MVC 的重点是在控制器中分离方法。如果您希望两个方法具有相同的行为,我建议修改您的控制器,使其具有一个 GET 和一个 POST,它们各自在控制器的其他地方调用相同的方法。

    但是您可以编写一个 Validation 属性来完成您想要的。

    基于此source code,您可以将Validation 属性中的OnAuthorization 方法编辑为:

    public void OnAuthorization(AuthorizationContext filterContext)
        {
            var request = filterContext.HttpContext.Request.HttpMethod;
            if (request != "GET")
            {
                if (filterContext == null)
                {
                    throw new ArgumentNullException("filterContext");
                }
    
                ValidateAction();
            }
        }
    

    现在检查请求是否为GET,在这种情况下它会跳过验证。完整的 Attribute 类是:

    using System.ComponentModel;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Web.Helpers;
    
    namespace System.Web.Mvc
    {
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class ValidateAntiForgeryTokenAttribute2 : FilterAttribute, IAuthorizationFilter
    {
        private string _salt;
    
        public ValidateAntiForgeryTokenAttribute2()
            : this(AntiForgery.Validate)
        {
        }
    
        internal ValidateAntiForgeryTokenAttribute2(Action validateAction)
        {
            Debug.Assert(validateAction != null);
            ValidateAction = validateAction;
        }
    
        [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "AdditionalDataProvider", Justification = "API name.")]
        [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "AntiForgeryConfig", Justification = "API name.")]
        [Obsolete("The 'Salt' property is deprecated. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.", error: true)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public string Salt
        {
            get { return _salt; }
            set
            {
                if (!String.IsNullOrEmpty(value))
                {
                    throw new NotSupportedException("The 'Salt' property is deprecated. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.");
                }
                _salt = value;
            }
        }
    
        internal Action ValidateAction { get; private set; }
    
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            var request = filterContext.HttpContext.Request.HttpMethod;
            if (request != "GET")
            {
                if (filterContext == null)
                {
                    throw new ArgumentNullException("filterContext");
                }
    
                ValidateAction();
            }
        }
    }
    

    }

    【讨论】:

      【解决方案3】:

      目前框架中没有任何内置功能可以让您执行此操作,但您仍然有一个选择。创建您自己的ValidateAntiForgeryToken 实现,该实现采用您希望对其进行验证的http verb/actions 参数。最简单的方法是实现接口IAuthorizationFilter

      【讨论】:

      • @lgor,感谢您的快速回复。但我得到了更好的解决方案,我将其标记为答案。
      • @Shanthini - 这是一个很好的答案并且易于实现,但是如果您需要在许多方法上执行此操作,那么在自定义 Filter 中编写一次代码比添加以上if 声明到你所有的方法。
      • @lgor 是的。我同意。但是目前我只在一种情况下遇到了这个问题:) 但是我确实创建了一个自定义过滤器以供将来参考;现在不用了。
      【解决方案4】:

      你有可能检测到这个see link

      if (HttpContext.Current.Request.HttpMethod == "POST")
      {
          // The action is a POST.
      }
      

      并且您需要一个方法属性在运行操作之前进行拦截并采取不同的行为来跳过操作。 ValidateAntiForgeryToken 不在 GET Using MVC3's AntiForgeryToken in HTTP GET to avoid Javascript CSRF vulnerability 上运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-30
        • 2011-11-12
        • 2016-12-14
        • 2013-11-04
        • 2018-10-19
        • 1970-01-01
        相关资源
        最近更新 更多