ASP.NET Core 入门教程 9、ASP.NET Core 中间件(Middleware)入门

摘要:
在Application中会有一个处理该请求的通道,这就是ASP.NETCore管道,通常称之为:请求处理管道在这个管道中,有一系列有序处理请求的组件,就是中间件。ASP.NETCore中会内置一些中间件,例如:身份验证、静态文件处理、MVC等。

一、前言

1、本教程主要内容

  • ASP.NET Core 中间件介绍
  • 通过自定义 ASP.NET Core 中间件实现请求验签

2、本教程环境信息

软件/环境说明
操作系统Windows 10
SDK2.1.401
ASP.NET Core2.1.3
MySQL8.0.x
IDEVisual Studio Code 1.32.3
浏览器Chrome 70
VS Code插件版本说明
C#1.17.1提供C#智能感知, .NET Core 调试、编译等
vscdoe-solution-explorer0.3.1提供解决方案视图

本篇代码以下代码进行调整:https://github.com/ken-io/asp.net-core-tutorial/tree/master/chapter-02

3、前置知识

可能需要的前置知识

  • C# 委托(Delegate)

http://www.runoob.com/csharp/csharp-delegate.html

  • C# 扩展方法

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

二、ASP.NET Core 中间件介绍

1、ASP.NET Core 中间件基本说明

当 ASP.NET Core MVC应用从Kestrel接收到请求,会建立HttpContext并交由Application来处理请求。在Application中会有一个处理该请求的通道,这就是ASP.NET Core 管道,通常称之为:请求处理管道

在这个管道中,有一系列有序处理请求的组件,就是中间件(Middleware)。

image

图中蓝色的部分可以认为是系统内置比较靠前的中间件或者我们自定义的中间件,MVC是一个特殊的中间件且通常放在最后,所以这里单独画出来

对于MVC中间件,如果请求的URL与路由匹配,那么后面的中间件均不会生效。所以MVC通常放在最后。

ASP.NET Core中会内置一些中间件,例如:身份验证、静态文件处理、MVC等。每个中间件在接受到请求后都可以选择是交由下一个中间件处理还是直接返回结果。例如:

  • 身份验证中间件验证未通过会直接引导到登陆页
  • 静态文件中间件判断为静态文件就会直接返回静态文件内容

所以,中间件可以理解为请求处理管道中的请求处理器。我们也可以通过自定义中间件注册到管道中来干预请求。

2、ASP.NET Core 中间件基础使用

在程序中,中间件是基于委托来构建的。在应用启动时通过IApplicationBuilder注册到通道中。

具体见启动类Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseMvc(routes =>
    {
        //配置默认路由
        routes.MapRoute(
            name: "Default",
            template: "{controller}/{action}",
            defaults: new { controller = "Home", action = "Index" }
        );
    });
}

UseDeveloperExceptionPageUseMvc都是接口IApplicationBuilder的扩展方法。

三、使用 ASP.NET Core 中间件实现请求验签

如果你开发的API是为手机App服务的,那么你的API是一定要暴露给公网的,如果有人拿到API地址进行非法请求,获取用户信息或者是篡改数据,用户隐私、数据就会受到损害。这是很不安全的,我们可以让客户端请求的时候必须携带签名,在服务器端鉴权(验证签名)通过了再放行,这样就安全很多了。

1、创建验签中间件

在项目Ken.Tutorial.Web创建目录Middlewares,然后创建类:TokenCheckMiddleware.cs

using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace Ken.Tutorial.Web.Middlewares
{
    public class TokenCheckMiddleware
    {
        private readonly RequestDelegate _next;
        public TokenCheckMiddleware(RequestDelegate requestDelegate)
        {
            this._next = requestDelegate;
        }
        public Task Invoke(HttpContext context)
        {
            //先从Url取token,如果取不到就从Form表单中取token
            var token = context.Request.Query["token"].ToString() ?? context.Request.Form["token"].ToString();
            if (string.IsNullOrWhiteSpace(token))
            {
                //如果没有获取到token信息,那么久返回token missing
                return context.Response.WriteAsync("token missing");
            }
            //获取前1分钟和当前的分钟
            var minute0 = DateTime.Now.AddMinutes(-1).ToString("yyyy-MM-dd HH:mm");
            var minute = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
            //当token和前一分钟或当前分钟任一时间字符串的MD5哈希一致,就认为是合法请求
            if (token == MD5Hash(minute) || token == MD5Hash(minute0))
            {
                return _next.Invoke(context);
            }
            //如果token未验证通过返回token error
            return context.Response.WriteAsync("token error");
        }
        public string MD5Hash(string value)
        {
            using (var md5 = MD5.Create())
            {
                var result = md5.ComputeHash(Encoding.ASCII.GetBytes(value));
                var strResult = BitConverter.ToString(result);
                return strResult.Replace("-", "");
            }
        }
    }
}

由于是侧重自定义中间件,所有验签的逻辑就写的非常简单,如果实际项目使用,可以按照自己需求调整

2、创建扩展方法

Middlewares目录下新建类:MiddlewareExtension.cs

using Microsoft.AspNetCore.Builder;
namespace Ken.Tutorial.Web.Middlewares
{
    public static class MiddlewareExtension
    {
        public static IApplicationBuilder UseTokenCheck(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<TokenCheckMiddleware>();
        }
    }
}

这里我们通过扩展方法,将TokenCheckMiddleware挂在接口IApplicationBuilder

3、中间件注册/引用

在启动类Startup.csConfigure方法中注册/引用中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //省略部分代码
    app.UseTokenCheck();
    app.UseMvc(routes =>
    {
        //省略路由配置代码
    });
}

如果你觉得扩展方法有点多余,也可以直接使用UseMiddleware方法注册

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //省略部分代码
    app.UseMiddleware<TokenCheckMiddleware>();
    app.UseMvc(routes =>
    {
        //省略路由配置代码
    });
}

这里要注意的是,如果你是一个MVC应用,请一定要把MVC这个中间件作为最后一个注册。因为中间件是按照注册顺序被调用的。如果放在MVC之后,请求的URL也有对应路由适配,那么整个请求已经被MVC接管。后面的中间件就不会被调用了。

4、验签中间件测试

启动应用,然后验证不同情况下的访问结果

URLResponse
localhost:5001token missing
localhost:5001?token=testtoken error
localhost:5001?token=3D76FEA1D0ADD0C7639B73023436C6EAHello World ! -ken.io

为了方便测试,MD5哈希的值我们可以在线生成:ttp://tool.chinaz.com/tools/md5.aspx

把当前分钟,例如:2019-03-27 23:23通过MD5在线生成那就是3D76FEA1D0ADD0C7639B73023436C6EA

四、备注

  • 本文代码示例

https://github.com/ken-io/asp.net-core-tutorial/tree/master/chapter-09

  • 本文参考

https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1

  • 延伸阅读

https://www.cnblogs.com/artech/p/inside-asp-net-core-pipeline.html


本文首发于我的独立博客:https://ken.io/note/asp.net-core-tutorial-middleware

免责声明:文章转载自《ASP.NET Core 入门教程 9、ASP.NET Core 中间件(Middleware)入门》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C#中 System.Threading.Timer 的回收问题springBoot项目里获取resource目录下的文件(可用于各种linux服务器部署)【我】下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

CheckBox实现跨页面多选

在很多程序中需要使用CheckBox的跨页面复选功能,本例实现了GridView多页复选功能SelectMultiPages.aspx  1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SelectMultiPages.aspx.cs" 2    Inherits="SelectMul...

ASP.NET Dynamic Data Part.2(自定义动态数据网站)

必须强调 3 点: 动态数据项目是基于 ASP.NET 构建的 动态数据依赖于一系列的模板,它们用于显示和编辑数据 动态数据应用中的一切都是可以进行自定义的 有很多方式可用来扩展、修改以及调整动态数据应用程序,因此,有时候对它们的选择会很困难。 使用模板进行自定义 模板是动态数据应用程序的核心。我将演示使用模板自定义数据被如何呈现到客户端的几个不同方式...

ASP.NET Web应用程序修改页面Inherits示例

<@page 中 Codebehind 、Inherits 和aspx的关系 CodeBehind 指定包含与页关联的类的已编译文件的名称。该属性不能在运行时使用。 说明: 提供此属性是为了与以前版本的 ASP.NET 的兼容,以实现代码隐藏功能。在 ASP.NET 2.0 版中,应改用 CodeFile 属性指定该源文件的名称,同时使用 Inher...

Hi3518EV300编译U-Boot和内核报错:loadlocale.c:130: _nl_intern_locale_data: Assertion `cnt &amp;lt; (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed. Aborted (core dumped)

下载Hi3518EV300的SDK后编译内核和U-boot,发现爆出如下错误: scripts/kconfig/conf --silentoldconfig Kconfig Aborted (core dumped) Aborted (core dumped) Aborted (core dumped) Aborted (core dumped) Abo...

docker 安装jumpserver

#docker 安装mkdir /etc/dockerecho "{    "registry-mirrors" : [    "https://registry.docker-cn.com",    "https://docker.mirrors.ustc.edu.cn",    "http://hub-mirror.c.163.com",    "ht...

JAVAWEB应用模块(一)登录模块

java后台代码(MD5加密+token验证): import com.smart.ssai.admin.domain.User; import com.smart.ssai.admin.service.UserService; import com.smart.ssai.VO.Response; import com.smart.ssai.common....