ActionFilters для получения идентификатора пользователя и возврата ошибки, если она пуста - PullRequest
1 голос
/ 05 февраля 2020

У меня есть базовый класс, от которого наследуются мои (api) контроллеры. Я сделал так, чтобы я мог получить идентификатор пользователя у своего провайдера аутентификации и использовать его позже, чтобы что-то делать с пользователем, обновлять его или получать его данные, и т. Д. c.

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, например, идентификатор имени, который мне нужен, чтобы найти пользователя. ни, честно говоря, как передать удостоверение личности обратно.

-UPDATE-

Теперь мне удалось заставить actionfilter возвращать ошибочный результат, когда пользователь не найден, поэтому половина того, что мне нужно, работает. Проблема в том, что теперь я вызываю DB, поскольку я все еще вызываю оригинальный BaseCass GetUserId, чтобы получить идентификатор, который будет использоваться в более поздних методах.

Чтобы получить ActionFilter для проверки пропавшего пользователя, я ввел в него свой текстовый текст :

private readonly NodeDBContext _context;

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

, а также использовал HttpContext из ActionExecutingContext, чтобы найти мой пользователь. на мой контроллер? Есть ли способ? или мне нужно дважды вызывать БД?

1 Ответ

1 голос
/ 06 февраля 2020

Проблема теперь в том, как мне вернуть «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();
        //...
    }
...