首页 > 解决方案 > ActionFilters 用于获取用户 ID 并在为 null 时返回错误

问题描述

我有一个基类,我的(api)控制器从中继承。我这样做是为了让我可以从我的身份验证提供者那里获取用户 ID,然后用它来处理用户、更新它或获取它的数据等。

public class BaseController : ControllerBase
{
    protected readonly IBaseData _baseData;

    public BaseController(IBaseData baseData)
    {
        _baseData = baseData;
    }

    public Guid GetUserId()
    {
        string nameIdentifier = User.FindFirst(ClaimTypes.NameIdentifier).Value;
        Guid? userId = _baseData.GetInvestorId(nameIdentifier);

        return userId != null ? (Guid)userId : Guid.Empty;
    }
}

然后我在我的 API 端点中调用它:

Guid userId = GetUserId();

BaseModel m = _userData.GetBaseModel(userId);

return Ok(m);

很简单。它在控制器中的多个位置被调用。不理想但工作正常。但是现在我需要捕获一个错误,该错误有时会在用户不在数据库中时发生。我可以向 API 端点添加一些代码来执行此操作:

Guid userId = GetUserId();

        if (userId == Guid.Empty)
            return NotFound(new ResponseGapiModel { Response = Response.NotFound, Message = "user not found in DB" });

        BaseModel m = _userData.GetBaseModel(userId);

        return Ok(m);

但这意味着我会在整个地方重复很多代码。我一直在尝试使用动作过滤器。但我无法理解它。我不知道如何在 actionfilter 中传递参数,比如我需要找到用户的名称标识符。也没有坦率地说如何将 ID 传回。

-更新-

我现在已经设法让 actionfilter 在找不到用户时返回失败的结果,所以我需要的一半有效。问题是现在我两次调用数据库,因为我仍然调用原始的 BaseCass GetUserId 来获取要在以后的方法中使用的 ID。

为了让 ActionFilter 检查丢失的用户,我将 datacontext 注入其中:

private readonly NodeDBContext _context;

    public ValidateAuth0UserInDBAttribute(NodeDBContext context)
    {
        _context = context;
    }

以及使用 ActionExecutingContext 中的 HttpContext 来查找我的用户 Nameidentifier:

public void OnActionExecuting(ActionExecutingContext context)
    {
        //check if the user it in DB
        var id = _context.Users.SingleOrDefault(i => i.NameIdentifier == context.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value)?.Id;

        if (id == null)
        {
            context.Result = new NotFoundObjectResult(new ResponseModel { Response = Response.UserNotFound, Message = "User not found in DB" });
            return;
        }
    }

现在的问题是我如何将“id”从这里传回给我的控制器?有办法吗?还是我必须两次调用数据库?

标签: c#asp.net-coreaction-filter

解决方案


现在的问题是我如何将“id”从这里传回给我的控制器?

尝试使用以下代码将 id 传递回控制器:

public class MyActionFilter : Attribute,IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        var id = _context.Users.SingleOrDefault(i => i.NameIdentifier == context.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value)?.Id;
        if (id == null)
        {
           context.Result = new NotFoundObjectResult(new ResponseModel { Response = Response.UserNotFound, Message = "User not found in DB" });
           return;
        }

        var controller = (ControllerBase)context.Controller;
        controller.HttpContext.Items.Add("CurrentUserId", id );

    }
    public void OnActionExecuted(ActionExecutedContext context) { }
}

行动:

[MyActionFilter]
public IActionResult Get()
    {
        var id = HttpContext.Items["CurrentUserId"]?.ToString();
        //...
    }

推荐阅读