【问题标题】:ASP.NET Core: How would I go about binding data from user claims?ASP.NET Core:我将如何从用户声明中绑定数据?
【发布时间】:2019-11-29 14:32:43
【问题描述】:

我有一个简单的 ASP.NET Core http API,并且有很多控制器操作都是这样开始的:

    public async Task<ActionResult> Delete()
    {
        if (!User.Claims.TryGetClaim("merchant_id", out long merchantId))
        {
            return BadRequest();
        }

        /* Real code using merchantId */
    }

我想减少每次索赔检查的重复次数,但我不确定如何去做。我的代码尽可能小,只使用扩展方法,但我想让它更小,像这样:

public async Task<ActionResult> Delete([FromClaims] long merchantId)
{
    /* Real code using merchantId */
}

但我一直在阅读有关 ASP.NET 核心中间件的文档,但我不知道我必须实现什么才能实现这一目标。

内置的FromBody 属性继承自IBindingSourceMetadata,它定义了一个BindingSource 属性。但是,我在网上找不到任何关于如何实现自己的绑定源以从用户声明中获取项目的资源。

【问题讨论】:

  • 我认为中间件可以解决您的问题
  • @dcg 嗯,我知道。这就是我的问题。
  • 您真的想要绑定,还是只是想要一种简单的方法来检索商家 ID?如果你想要一些可以注入服务等的东西,我可以分享一些我用于类似的代码。
  • 如果您添加中间件,您仍然需要检查每个操作方法。角色也是声明,因此您可以制定自定义策略并添加 [Authorize(Policy = "CustomPolicy")] 控制器范围。或覆盖控制器中的“OnActionExecuting”以检查控制器范围
  • 我想我实际上不需要绑定,只是要求和获取商家 ID 的简单方法

标签: c# asp.net-core model-view-controller model-binding


【解决方案1】:

您可以将策略库授权与属性一起使用。

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddAuthorization(options =>
    {
        options.AddPolicy("ShouldHaveMerchantId", policy => 
              policy.RequireClaim("merchant_id"));
    });
    ...
}

并且在您的操作方法上使用 Authorize 属性和您的策略名称。

[Authorize(Policy = "ShouldHaveMerchantId")]
public async Task<IActionResult> YourActionMethod()
{
    //Your logic
}

【讨论】:

  • 我认为这是最好的 imo,只是现在您仍然需要在每个操作方法中解析它
  • 正如@Marcel 所说,这优雅地解决了一半的问题。我仍然需要一种在每个操作方法中获取此声明内容的方法。
  • 你必须将两者结合起来
【解决方案2】:

你可以创建这样的中间件

public class MyMiddleware 
{
   private readonly RequestDelegate next;

   public MyMiddleware (RequestDelegate next)
   {
        this.next = next;
   }

   public async Task Invoke(HttpContext ctx) 
   {
       // Your check here, something like
       if (!ctx.User.Claims.TryGetClaim("merchant_id", out long merchantId))
       {
            ctx.Response.StatusCode = (int)HttpStatusCode.BadRequest;
       }
       else
       {
            await next.Invoke(ctx);
       }

   }
}

然后像这样注册

app.UseMiddleware<MyMiddleware>();

【讨论】:

  • 如果这只适用于某些控制器操作怎么办?
  • 你可以访问整个HttpContext对象,所以你可以先做一些过滤
  • 我认为在这种情况下使用自定义AuthorizationHandler 会更好。然后,您可以使用属性而不是在中间件中过滤来装饰必要的控制器操作。
  • 我建议使用中间件,因为 OP 说很多动作都是以同样的方式开始的。
  • 如果这是他的应用程序的规范,那么您并没有错。我只是假设(我知道,这不是一个好主意哈哈)“很多动作都以相同的方式开始”而且“很多动作不会(或不会)以相同的方式开始。”跨度>
猜你喜欢
  • 2019-10-01
  • 2018-12-16
  • 1970-01-01
  • 1970-01-01
  • 2017-03-22
  • 2017-09-25
  • 1970-01-01
  • 1970-01-01
  • 2022-06-30
相关资源
最近更新 更多