DelegateHandler из ASP.NET в .NET Core - PullRequest
0 голосов
/ 30 августа 2018

В старом проекте asp.net у меня есть класс, который реализует DelegatingHandler, который я установил для каждого маршрута:

public class AdminSecurityMessageHandler : DelegatingHandler
{
    private readonly HttpConfiguration _config;

    public AdminSecurityMessageHandler(HttpConfiguration config)
    {
        if (config == null)
        {
            throw new ArgumentNullException("config");
        }
        _config = config;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var repository = (IUserRepository)_config.DependencyResolver.GetService(typeof(IUserRepository));
        var accessTokener = (IAccessTokener)_config.DependencyResolver.GetService(typeof(IAccessTokener));

        if (!request.Headers.Contains(AccessTokener.CallerId))
        {
            return Unauthorized(String.Empty);
        }

        var guid = request.Headers.GetValues(AccessTokener.CallerId).FirstOrDefault();
        var user = repository.GetByGuid(guid);

        if (user == null)
        {
            return Unauthorized(String.Empty);
        }

        var result = accessTokener.CheckAccessTokenHash(user.Guid, request.Headers.Authorization.Parameter);
        switch (result)
        {
            case AccessTokenCheckerResult.Invalid:
                return Unauthorized(String.Empty);
            case AccessTokenCheckerResult.Expired:
                return Unauthorized("AccessToken.Expired");
        }

        if (!user.IsAdmin)
        {
            return Unauthorized("No admin rights");
        }

        var claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.Name, user.Id.ToString()));
        var identity = new ClaimsIdentity(claims, "custom");
        var principal = new UserPrincipal(identity, user);
        request.GetRequestContext().Principal = principal;

        return base.SendAsync(request, cancellationToken);
    }

Мне нужно переместить проект в .NET Core, и у меня возникают некоторые проблемы при попытке их зарегистрировать. Я могу зарегистрировать простые маршруты, как это:

app.UseMvc(routes => { routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}"); });

Итак, вопрос в том, как мне реализовать и настроить что-то вроде DelegatingHandler в ASP.NET при регистрации маршрутов в .NET Core? (Установить другой обработчик для маршрута)

Как это работает в ASP.NET: Зарегистрируйте метод в WebApiConfig классе.

public static void RegisterRoutes(HttpConfiguration config, HttpMessageHandler routeHandlers, HttpMessageHandler adminRouteHandlers)
{
    .......................

    config.Routes.MapHttpRoute(
        name: "FriendsAPI",
        routeTemplate: "api/users/{id}/friends/{friendId}",
        defaults: new { controller = "Friends", friendId = RouteParameter.Optional },
        constraints: null,
        handler: routeHandlers
    );


    config.Routes.MapHttpRoute(
        name: "AdminUserBlocksApi",
        routeTemplate:
            "api/admin/user-blocks/{userId}",
        defaults: new { controller = "AdminUserBlocks", userId = RouteParameter.Optional },
        constraints: null,
        handler: adminRouteHandlers
    .......................
    );
}

1 Ответ

0 голосов
/ 30 августа 2018

Поскольку в Asp.Net Core нет DelegateHandlers, вы можете попробовать создать пользовательский middleware. См. Упрощенный middleware, который вы можете использовать для удовлетворения ваших требований:

public class AdminSecurityMiddleware
{
    private readonly RequestDelegate _next;
    IUserRepository userRepository; // IUserRepository should be registered for dependency injection in Startup.ConfigureServices

    public AdminSecurityMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        bool isAdminUserBlocksApiRoute; 
        //check for route here. As I know there is no elegant way to get name of the route since context.GetRouteData() returns null until mvc middleware is called.
        // probably you can check like this context.Request.Path.StartsWithSegments("/api/admin")

        if (isAdminUserBlocksApiRoute)
        {
            _userRepository = context.RequestServices.GetService<IUserRepository>();
            bool isUserAuthorized;
            // check here for Authorization
            if (!isUserAuthorized)
            {
                context.Response.Clear();
                context.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                await context.Response.WriteAsync("Unauthorized");
                return;
            }

            // adding custom claims
            var identity = new ClaimsIdentity(new GenericIdentity("user.Id"), new[] { new Claim("user_id", "id") });
            context.User.AddIdentity(identity);
        }
        await _next.Invoke(context);
    }
}

Затем добавьте его в конвейер до mvc middleware in Startup:

app.UseMiddleware<AdminSecurityMiddleware>();
app.UseMvc(routes =>
{
    ...
}

Подробнее о промежуточном программном обеспечении здесь

...