Чтение HttpContext.Request как объекта? - PullRequest
0 голосов
/ 21 марта 2020

Мой базовый Request класс выглядит следующим образом:

public class GetAllProjectsQuery : QueryBase<ProjectsListModel>
{
}

public abstract class QueryBase<T> : UserContext, IRequest<T> // IRequest is MediatR interface
{
}

public abstract class UserContext
{
    public string ApplicationUserId { get; set; } // and other properties
}

Я хочу написать промежуточное программное обеспечение для моего .NET Core 3.1 WebApi, которое будет извлекать JWT из заголовка запроса и читать из него ApplicationUserId. Я начал что-то кодировать:

public class UserInformation
{
    private readonly RequestDelegate next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        var jwt = context.Request.Headers["Authorization"];
        // read jwt here
        var userContext = (UserContext)context.Request.Body; // i know it wont work
        userContext.ApplicationUserId = //whats next? Any ideas?

        await this.next(context);
    }
}

Но, честно говоря, я не знаю, с чего начать, поэтому вот мои вопросы:

Как видите, каждый запрос будет упакован с моим UserContext класс и тд. Как привести HttpContext.Request.Body к моему объекту запроса и прикрепить к нему ApplicationUserId? Является ли это возможным? Я хочу получить доступ к учетным данным пользователя из моего JWT из заголовков, и я хочу иметь эту информацию в каждом запросе в моем API (передать его контроллеру, затем команде et c).

Если получение этой информации из промежуточного программного обеспечения не является наилучшей практикой, что это такое?

РЕДАКТИРОВАТЬ: Mcontroller, использующий MediatR:

// base controller:
[ApiController]
[Route("[controller]")]
public abstract class BaseController : ControllerBase
{
    private IMediator mediator;

    protected IMediator Mediator => this.mediator ?? (this.mediator = HttpContext.RequestServices.GetService<IMediator>());
}

// action in ProjectControlle

[HttpGet]
[Authorize]
public async Task<ActionResult<ProjectsListModel>> GetAllProjects()
{
    return Ok(await base.Mediator.Send(new GetAllProjectsQuery()));
}

// query:
public class GetAllProjectsQuery : QueryBase<ProjectsListModel>
{
}

// handler:

public class GetAllProjectsQueryHandler : IRequestHandler<GetAllProjectsQuery, ProjectsListModel>
{
    private readonly IProjectRepository projectRepository;

    public GetAllProjectsQueryHandler(IProjectRepository projectRepository)
    {
        this.projectRepository = projectRepository;
    }

    public async Task<ProjectsListModel> Handle(GetAllProjectsQuery request, CancellationToken cancellationToken)
    {
        var projects = await this.projectRepository.GetAllProjectsWithTasksAsync();

        return new ProjectsListModel
        {
            List = projects
        };
    }
}

1 Ответ

1 голос
/ 21 марта 2020

Возможно, вам не понадобится промежуточное программное обеспечение, но вам нужно связующее для моделей:

См .: https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1

См. Также: https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-3.1

public class UserContextModelBinder : IModelBinder
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IModelBinder _defaultModelBinder;

    public UserContextModelBinder(
        IHttpContextAccessor httpContextAccessor,
        IOptions<MvcOptions> mvcOptions,
        IHttpRequestStreamReaderFactory streamReaderFactory)
    {
        _httpContextAccessor = httpContextAccessor;
        _defaultModelBinder = new BodyModelBinder(mvcOptions.Value.InputFormatters, streamReaderFactory);
    }

    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (!typeof(UserContext).IsAssignableFrom(bindingContext.ModelType))
        {
            return;
        }

        await _defaultModelBinder.BindModelAsync(bindingContext);

        if (bindingContext.Result.IsModelSet && bindingContext.Result.Model is UserContext)
        {
            var model = (UserContext)bindingContext.Result.Model;
            var httpContext = _httpContextAccessor.HttpContext;

            // Read JWT
            var jwt = httpContext.Request.Headers["Authorization"];

            model.ApplicationUserId = jwt;

            bindingContext.Result = ModelBindingResult.Success(model);
        }
    }
}

Затем добавьте связыватель модели в класс UserContext:

[ModelBinder(typeof(UserContextModelBinder))]
public abstract class UserContext
{
    public string ApplicationUserId { get; set; }
}

Также добавьте IHttpContextAccessor к службам в Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddHttpContextAccessor();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...