乐趣区

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

一、前言
1、本教程主要内容

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

2、本教程环境信息

软件 / 环境
说明

操作系统
Windows 10

SDK
2.1.401

ASP.NET Core
2.1.3

MySQL
8.0.x

IDE
Visual Studio Code 1.32.3

浏览器
Chrome 70

VS Code 插件
版本
说明

C#
1.17.1
提供 C# 智能感知,.NET Core 调试、编译等

vscdoe-solution-explorer
0.3.1
提供解决方案视图

本篇代码以下代码进行调整:https://github.com/ken-io/asp…
3、前置知识
可能需要的前置知识
C# 委托(Delegate)
http://www.runoob.com/csharp/…
C# 扩展方法
https://docs.microsoft.com/zh…
二、ASP.NET Core 中间件介绍
1、ASP.NET Core 中间件基本说明
当 ASP.NET Core MVC 应用从 Kestrel 接收到请求,会建立 HttpContext 并交由 Application 来处理请求。在 Application 中会有一个处理该请求的通道,这就是 ASP.NET Core 管道,通常称之为:请求处理管道
在这个管道中,有一系列有序处理请求的组件,就是中间件(Middleware)。

图中蓝色的部分可以认为是系统内置比较靠前的中间件或者我们自定义的中间件,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”}
);
});
}
UseDeveloperExceptionPage、UseMvc 都是接口 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.cs 的 Configure 方法中注册 / 引用中间件
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、验签中间件测试
启动应用,然后验证不同情况下的访问结果

URL
Response

localhost:5001
token missing

localhost:5001?token=test
token error

localhost:5001?token=3D76FEA1D0ADD0C7639B73023436C6EA
Hello World!-ken.io

为了方便测试,MD5 哈希的值我们可以在线生成:ttp://tool.chinaz.com/tools/md5.aspx
把当前分钟,例如:2019-03-27 23:23 通过 MD5 在线生成那就是 3D76FEA1D0ADD0C7639B73023436C6EA
四、备注
本文代码示例
https://github.com/ken-io/asp…
本文参考
https://docs.microsoft.com/zh…
延伸阅读
https://www.cnblogs.com/artec…

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

退出移动版