在 ActionFilterAttribute 中从 .NET Core Web API 上的请求正文获取 JSON 数据

问题描述 投票:0回答:2

我正在编写一个自定义 ActionFilterAttribute,以便在请求命中 .Net Core Web API 中的操作之前处理一些业务逻辑。 (核心v1.1) OnActionExecuting 已成功命中处理程序,但我无法提取来自请求正文的以 JSON 格式发送的数据。

我尝试了几种方法,例如读取 ActionExecutingContext 流主体(为空)、访问 Form 属性(但由于它是 json,因此不起作用)以及其他一些解决方案,但没有运气。

这是我的 ActionFilter 的代码,它是空的,因为这里的问题基本上是需要提取其数据,所以进一步的代码是无关紧要的。

public class AccountRestrictionAttribute : ActionFilterAttribute
{
     public override async void OnActionExecuting(ActionExecutingContext context)
     {      
     }
}
.net asp.net-web-api action-filter asp.net-core-webapi
2个回答
2
投票

答案归功于rynowak,我在这里找到了它https://github.com/aspnet/Mvc/issues/5260

ModelBinding 在操作过滤器之前运行,因此如果您有表单数据或 [FromBody] 参数,我们已经读取了它。

是的,如果您位于操作过滤器中,则 context.ActionArguments 将包含我们创建的所有模型对象。所以如果你有:

public IActionResult Edit(int id, [FromBody] Widget widget) { }

然后 context.ActionArguments["widget"] 将返回 Widget 对象。如果您尝试以通用方式执行此操作,请查看 context.ActionDescriptor.Parameters - 这将包含所有参数定义和元数据。


0
投票

如果您想读取操作过滤器内的请求正文,您需要使用

StreamReader
并启用缓冲,如下例所示...

public class AccountRestrictionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var body = string.Empty;
        var request = context.HttpContext.Request;

        request.EnableBuffering();
        if(request.Body.CanSeek) request.Body.Position = 0;

        using (var s = new StreamReader(request.Body, encoding: Encoding.UTF8,
            detectEncodingFromByteOrderMarks: false, leaveOpen: true))
        {
            body = s.ReadToEnd();
        }

        var account = JsonConvert.DeserializeObject(body);
        //account restriction logic below
    }
}

我将流保持打开状态,以防您想在不同的中间件(例如日志记录)中进行进一步处理。以下是在请求中发送的以下 JSON 的示例...

{
    "id": 123,
    "email": "[email protected]",
    "name": "John Smith",
    "role": "Admin"
}

以及 VS 中带有断点的调试屏幕截图...

不要忘记用动作过滤器注释动作方法...

    [HttpPost(""), AccountRestriction]
    public IResult RestrictedArea()
    {
        ...
    }

您甚至可以将参数传递给操作过滤器...

    [HttpPost(""), AccountRestriction(AllowedRoles = "Admin,Supervisor")]
    public IResult RestrictedArea()
    {
        ...
    }

然后处理传入的参数...

public class AccountRestrictionAttribute : ActionFilterAttribute
{
    public string AllowedRoles { get; set; } = string.Empty;

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        //code ommitted for better clarity...

        var account = JsonConvert.DeserializeObject<AccountModel>(body);
        var roles = AllowedRoles.Split(',', options: StringSplitOptions.RemoveEmptyEntries);

        if (roles.Contains(account.Role.ToString()))
        {
            var allowedRoles = context.ActionArguments[AllowedRoles];    
            context.Result = new UnauthorizedResult();
        }
    }
}

重要!!!

请勿将其用于访问控制或授权目的。推荐的请求授权方式是通过访问令牌。

© www.soinside.com 2019 - 2024. All rights reserved.