从 ASP.NET 到 .NET Core 的 DelegateHandler [英] DelegateHandler from ASP.NET to .NET Core

查看:19
本文介绍了从 ASP.NET 到 .NET Core 的 DelegateHandler的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个旧的 asp.net 项目中,我有一个类实现了我为每个路由设置的 DelegatingHandler:

公共类AdminSecurityMessageHandler : DelegatingHandler{私有只读 HttpConfiguration _config;公共 AdminSecurityMessageHandler(HttpConfiguration 配置){如果(配置 == 空){throw new ArgumentNullException("config");}_config = 配置;}受保护的覆盖任务发送异步(HttpRequestMessage 请求,CancellationToken 取消令牌){var repository = (IUserRepository)_config.DependencyResolver.GetService(typeof(IUserRepository));var accessTokener = (IAccessTokener)_config.DependencyResolver.GetService(typeof(IAccessTokener));如果 (!request.Headers.Contains(AccessTokener.CallerId)){返回未授权(String.Empty);}var guid = request.Headers.GetValues(AccessTokener.CallerId).FirstOrDefault();var user = repository.GetByGuid(guid);如果(用户==空){返回未授权(String.Empty);}var result = accessTokener.CheckAccessTokenHash(user.Guid, request.Headers.Authorization.Parameter);切换(结果){案例 AccessTokenCheckerResult.Invalid:返回未授权(String.Empty);案例 AccessTokenCheckerResult.Expired:return Unauthorized("AccessToken.Expired");}如果 (!user.IsAdmin){return Unauthorized("无管理员权限");}var claim = new List();claim.Add(new Claim(ClaimTypes.Name, user.Id.ToString()));var identity = new ClaimsIdentity(claims, "custom");var principal = new UserPrincipal(identity, user);request.GetRequestContext().Principal = principal;返回 base.SendAsync(请求,取消令牌);}

我需要将项目移至 .NET Core,并且在尝试注册它们时遇到了一些麻烦.我可以像这样注册简单的路由:

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

所以问题是当我在 .NET Core 中注册路由时,我应该如何从 ASP.NET 实现和设置类似 DelegatingHandler 的东西?(为每个路由设置不同的处理程序)

它在 ASP.NET 中的工作原理:WebApiConfig 类中的注册方法.

public static void RegisterRoutes(HttpConfiguration config, HttpMessageHandler routeHandlers, HttpMessageHandler adminRouteHandlers){……………………config.Routes.MapHttpRoute(name: "FriendsAPI",routeTemplate: "api/users/{id}/friends/{friendId}",默认值:新 { 控制器 = 朋友",friendId = RouteParameter.Optional },约束:空,处理程序:路由处理程序);config.Routes.MapHttpRoute(name: "AdminUserBlocksApi",路线模板:"api/admin/user-blocks/{userId}",默认值:新 { 控制器 = "AdminUserBlocks",用户 ID = RouteParameter.Optional },约束:空,处理程序:adminRouteHandlers……………………);}

解决方案

由于 Asp.Net Core 中没有 DelegateHandlers 你可以尝试创建一个自定义的 中间件.查看简化的中间件,您可以使用它来满足您的要求:

公共类AdminSecurityMiddleware{私有只读 RequestDelegate _next;IUserRepository userRepository;//IUserRepository 应该在 Startup.ConfigureServices 中注册依赖注入public AdminSecurityMiddleware(RequestDelegate next){_next = 下一个;}公共异步任务调用(HttpContext 上下文){bool isAdminUserBlocksApiRoute;//在这里检查路线.据我所知,没有优雅的方法来获取路由的名称,因为 context.GetRouteData() 在调用 mvc 中间件之前返回 null.//也许你可以像这样检查 context.Request.Path.StartsWithSegments("/api/admin")如果(isAdminUserBlocksApiRoute){_userRepository = context.RequestServices.GetService();bool isUserAuthorized;//在这里检查授权如果 (!isUserAuthorized){context.Response.Clear();context.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;等待 context.Response.WriteAsync("未授权");返回;}//添加自定义声明var identity = new ClaimsIdentity(new GenericIdentity("user.Id"), new[] { new Claim("user_id", "id") });context.User.AddIdentity(身份);}等待_next.Invoke(上下文);}}

然后在启动中的mvc middleware之前将其添加到pipeline中:

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

阅读有关中间件的更多信息此处

In an old asp.net project I have a class that implements DelegatingHandler that I set to each route:

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);
    }

I need to move the project to .NET Core, and I have some troubles when trying to register them. I can register simple routes like this:

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

So the question is how should I implement and set something like DelegatingHandler from ASP.NET when I register routes in .NET Core? (Set different handler per route)

How it works in ASP.NET: Register method in WebApiConfig class.

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
    .......................
    );
}

解决方案

Since there is no DelegateHandlers in Asp.Net Core you can try to create a custom middleware. See the simplified middleware that you can use to meet your requirements:

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);
    }
}

Then add it to pipeline before mvc middleware in Startup:

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

Read more about middleware here

这篇关于从 ASP.NET 到 .NET Core 的 DelegateHandler的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆