【问题标题】:Overwrite request object in ASP .NET Core覆盖 ASP .NET Core 中的请求对象
【发布时间】:2021-01-21 22:21:56
【问题描述】:

我的应用程序中的每个请求都有base 类:

public abstract class BaseDto
{
   public string Uid { get; set; }
}

public class RequestDto : BaseDto
{
    public string SomeData { get; set; }
}

我在我的控制器操作中使用我的 ReuqestDto 类:

[HttpGet]
public IEnumerable<string> Get(RequestDto req)
{
    // some logic on request
    if (req.Uid != null)
    {
        // perform action
    }

}

用户只将SomeData 属性传递给我。在我的 JWT 令牌中,我为 BaseDto 保存了一些关于 Uid 的信息。使用中间件/过滤器将数据写入Uid 以在我的Get() 方法中包含该信息的最佳方法是什么?我试图序列化HttpContext.Request.Body 但没有成功,因为我找不到,如何正确地做到这一点。或者也许有更好的解决方案来解决这个问题?如何将数据写入应用程序中的传入对象?

【问题讨论】:

  • 模型绑定属性可能会有所帮助。 docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding
  • 那或使用请求过滤器。在中间件中做这件事可能还为时过早。
  • 感谢您的建议,您能否在评论中提供答案,如何覆盖 .net 核心中的请求对象?可以过滤。我只是想知道在 webapi 中是否有可能

标签: c# asp.net-core .net-core asp.net-core-3.1


【解决方案1】:

这可能就是你想要的。

你应该为这样的模型创建自己的界面

public interface IMyRequestType { }

您的模型应该实现它以在 FilterAttribute 中查找模型

public class MyModel : IMyRequestType
{
    public string ID { get; set; }
}

并使用OnActionExecuting 实现创建您的过滤器属性

public class MyFilterAttribute : TypeFilterAttribute
{
    public MyFilterAttribute() : base(typeof(MyFilterImpl)) { }

    private class MyFilterImpl : IActionFilter
    {
        private readonly ILogger _logger;

        public MyFilterAttributeImpl(ILoggerFactory loggerFactory)
        {
            // get something from DI
            _logger = loggerFactory.CreateLogger<MyFilterAttributeImpl>();
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            // get your request model
            var model = context.ActionArguments.Values.OfType<IMyRequestType>().Single();

            // get your key
            //context.HttpContext.User or whatever

            // do something with model
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // perform some logic work
        }
    }
}

【讨论】:

    【解决方案2】:

    我经常创建一个实现AttributeIAsyncActionFilter 的过滤器,以便在进入控制器的操作之前获取信息。

    这是一个例子,

    using System.IdentityModel.Tokens.Jwt;
    
     public class UserProfileFilter : Attribute, IAsyncActionFilter
     {
            public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
            {
                string uid = string.Empty;
                StringValues authHeaderVal = default(StringValues);
    
                // Get UID from JWT
                if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out authHeaderVal))
                {
                    string bearerTokenPrefix = "Bearer";
                    string accessToken = string.Empty;
                    string authHeaderStr = authHeaderVal.ToString();
                    if (!string.IsNullOrEmpty(authHeaderStr) && authHeaderStr.StartsWith(bearerTokenPrefix, StringComparison.OrdinalIgnoreCase))
                    {
                        accessToken = authHeaderStr.Replace(bearerTokenPrefix, string.Empty, StringComparison.OrdinalIgnoreCase).Trim();
                    }
    
                    var handler = new JwtSecurityTokenHandler();
                    var token = handler.ReadJwtToken(accessToken);
                    uid = token.Claims.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value;
                }
    
                // Or Get UID from ActionExecutingContext
                var user = context.HttpContext.User;
                if (user.Identity.IsAuthenticated)
                {
                    uid = user.Claims.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value;
                }
    
                // Get payload
                RequestDto payload = (RequestDto)context.ActionArguments?.Values.FirstOrDefault(v => v is RequestDto);
                payload.Uid = uid;
    
                await next();
            }
    }
    

    然后您可以将过滤器放在任何操作上。

    [HttpPost]
    [Authorize]
    [TypeFilter(typeof(UserProfileFilter))]
    public ActionResult<IActionResult> AdminGet(RequestDto request)
    {           
       Debug.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(request));
       return this.Ok();
    }
    
    

    上述过滤器将使用 sub 声明的值来覆盖传入负载的值。

    例如,如果我将有效负载发布如下,

    {
        "uid" : "",
        "someData": "Test"
    }
    

    动作最终会输出{"Uid":"MyID","SomeData":"Test"}

    【讨论】:

      猜你喜欢
      • 2017-07-26
      • 2021-08-19
      • 2022-11-02
      • 2021-08-18
      • 1970-01-01
      • 2022-10-19
      • 1970-01-01
      • 2021-08-21
      • 2020-06-26
      相关资源
      最近更新 更多