通过构造函数将方法参数发送到动作过滤器

时间:2019-01-25 21:32:42

标签: c# asp.net-core asp.net-core-mvc asp.net-core-2.1

我正在ASP.NET Core中建立一个网站,我刚刚开始设置一些过滤器来控制对某些方法的访问,而某些方法的标准之一就是请求的Referer标头。

我想通过构造函数将引荐来源网址的有效URL作为参数发送给操作过滤器。

我创建了以下过滤器:

public class RefererFilter : ActionFilterAttribute
{
    private List<string> referers;

    public RefererFilter(params string[] _referers)
    {
        referers = new List<string>(_referers);
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        bool valid = false;

        foreach (string referer in referers)
        {
            if (context.HttpContext.Request.Headers["Referer"].ToString() == ("https://" + context.HttpContext.Request.Host.Value + referer))
            {
                valid = true;
                break;
            }
        }

        if (!valid)
            context.Result = new StatusCodeResult(403);

        base.OnActionExecuting(context);
    }
}

我想这样使用它:

[RefererFilter("/Users/ChangePassword/" + id)]
public IActionResult PasswordChanged(int id)
{
    return View();
}

问题在于过滤器调用中不存在变量“ id”。

我知道还有其他方法可以通过知道方法中的名称从动作过滤器中获取属性,但这将迫使我创建各种过滤器,因为URL并非都遵循相同的结构。 / p>

有什么办法可以做到吗?

1 个答案:

答案 0 :(得分:0)

然后仅让过滤器知道操作参数的名称。那是过滤器需要知道的唯一一件事。

您是否注意到HttpGetAttribute也通过传递参数名称来做到这一点

        [HttpGet("{id}")]
        public string Get(int id)
        {

请记住,花括号在URI中无效(请参阅RFC 3986)。因此,我们可以安全地将其用作符号,稍后将其替换为操作参数值。因此,您可以使url模板变成这样,

    [RefererFilter("/Users/ChangePassword/{id}")]
    public IActionResult PasswordChanged(int id)
    {
        return View();
    }

    [RefererFilter("/Users/EditUser/{id}/UserEmail/{email}")]
    public IActionResult EditUser(int id, string email)
    {
        return View();
    }

然后,在RefererFilter中,您将需要解析OnActionExecuting方法中的action参数的值,如下所示,

    public class RefererFilter : ActionFilterAttribute
    {
        private List<string> referers;

        public RefererFilter(params string[] _referers)
        {
            referers = new List<string>(_referers);
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            bool valid = false;

            foreach (string referer in referers)
            {
                string r = referer;
                foreach(var arg in context.ActionArguments)
                {
                    r = r.Replace($"{{{arg.Key}}}", arg.Value.ToString());
                }

                if (context.HttpContext.Request.Headers["Referer"].ToString() == $"https://{context.HttpContext.Request.Host.Value}{r}")
                {
                    valid = true;
                    break;
                }
            }

            if (!valid)
                context.Result = new StatusCodeResult(403);

            base.OnActionExecuting(context);
        }
    }