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.net-core-tutorial/tree/master/chapter-02
3、前置知識
可能需要的前置知識
C# 委託(Delegate)
http://www.runoob.com/csharp/csharp-delegate.html
二、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" }
);
});
}
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.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