asp.net core利用DI實現自定義用戶系統,脫離ControllerBase.User

来源:http://www.cnblogs.com/nickppa/archive/2017/05/25/6903694.html
-Advertisement-
Play Games

前言 很多時候其實我們並不需要asp.net core自帶的那麼複雜的用戶系統,基於角色,各種概念,還得用EF Core,而且在web應用中都是把信息存儲到cookie中進行通訊(我不喜歡放cookie中,因為有次我在mac系統中的safari瀏覽器運行web應用時,碰到跨域cookie設不上,非要 ...


前言

很多時候其實我們並不需要asp.net core自帶的那麼複雜的用戶系統,基於角色,各種概念,還得用EF Core,而且在web應用中都是把信息存儲到cookie中進行通訊(我不喜歡放cookie中,因為有次我在mac系統中的safari瀏覽器運行web應用時,碰到跨域cookie設不上,非要使用個很特殊的方法,記得是iframe,挺麻煩的,所以我還是喜歡放自定義header中), 用了以後感覺被微軟給綁架了。不過這完全是個人喜好,大家完全可以按自己喜歡的來,我這裡提供了另外一條路,大家可以多一種選擇。

我這邊是利用asp.net core的依賴註入,定義了一套屬於自己系統的用戶認證與授權,大家可以參考我這個來定義自己的,也不局限於用戶系統。

面向切麵編程(AOP)

在我看來,Middleware與Filter都是asp.net core中的切麵,我們可以把認證與授權放到這兩塊地方。我個人比較喜歡把認證放到Middleware,可以提早把那些不合法的攻擊攔截返回。

依賴註入(DI)

依賴註入有3種生命周期

1. 在同一個請求發起到結束。(services.AddScoped)

2. 每次註入的時候都是新建。(services.AddTransient)

3. 單例,應用開始到應用結束。(services.AddSingleton)

我的自定義用戶類採用的是services.AddScoped。

具體做法

1. 定義用戶類

1     // 用戶類,隨便寫的
2     public class MyUser
3     {
4         public string Token { get; set; }
5         public string UserName { get; set; }
6     }

2. 註冊用戶類

Startup.cs中的ConfigureServices函數:

1         // This method gets called by the runtime. Use this method to add services to the container.
2         public void ConfigureServices(IServiceCollection services)
3         {
4             ...
5             // 註冊自定義用戶類
6             services.AddScoped(typeof(MyUser));
7             ...
8         }

自定義用戶類,是通過services.AddScoped方式進行註冊的,因為我希望它在同一個請求中,Middleware, filter, controller引用到的是同一個對象。

3. 註入到Middleware

 1     // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
 2     public class AuthenticationMiddleware
 3     {
 4         private readonly RequestDelegate _next;
 5         private IOptions<HeaderConfig> _optionsAccessor;
 6 
 7         public AuthenticationMiddleware(RequestDelegate next, IOptions<HeaderConfig> optionsAccessor)
 8         {
 9             _next = next;
10             _optionsAccessor = optionsAccessor;
11         }
12 
13         public async Task Invoke(HttpContext httpContext, MyUser user)
14         {
15             var token = httpContext.Request.Headers[_optionsAccessor.Value.AuthHeader].FirstOrDefault();
16             if (!IsValidate(token))
17             {
18                 httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
19                 httpContext.Response.ContentType = "text/plain";
20                 await httpContext.Response.WriteAsync("UnAuthentication");
21             }
22             else
23             {
24                 // 設置用戶的token
25                 user.Token = token;
26                 await _next(httpContext);
27             }
28         }
29 
30         // 隨便寫的,大家可以加入些加密,解密的來判斷合法性,大家自由發揮
31         private bool IsValidate(string token)
32         {
33             return !string.IsNullOrEmpty(token);
34         }
35     }
36 
37     // Extension method used to add the middleware to the HTTP request pipeline.
38     public static class AuthenticationMiddlewareExtensions
39     {
40         public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder)
41         {
42             return builder.UseMiddleware<AuthenticationMiddleware>();
43         }
44     }

我發現如果要把介面/類以Scoped方式註入到Middleware中,就需要把要註入的類/介面放到Invoke函數的參數中,而不是Middleware的構造函數中,我猜這也是為什麼Middleware沒有繼承基類或者介面,在基類或者介面中定義好Invoke的原因,如果它在基類或者介面中定義好Invoke,勢必這個Invoke的參數要固定死,就不好依賴註入了。

4. 配置某些路徑才會使用該Middleware

 1         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
 2         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 3         {
 4             loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 5             loggerFactory.AddDebug();
 6             // Set up nlog
 7             loggerFactory.AddNLog();
 8             app.AddNLogWeb();
 9 
10             // 除了特殊路徑外,都需要加上認證的Middleware
11             app.MapWhen(context => !context.Request.Path.StartsWithSegments("/api/token")
12                                  && !context.Request.Path.StartsWithSegments("/swagger"), x =>
13             {
14                 // 使用自定義的Middleware
15                 x.UseAuthenticationMiddleware();
16                 // 使用通用的Middleware
17                 ConfigCommonMiddleware(x);
18             });
19             // 使用通用的Middleware
20             ConfigCommonMiddleware(app);
21 
22             // Enable middleware to serve generated Swagger as a JSON endpoint.
23             app.UseSwagger();
24 
25             // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
26             app.UseSwaggerUI(c =>
27             {
28                 c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
29             });
30         }
31 
32         // 配置通用的Middleware
33         private void ConfigCommonMiddleware(IApplicationBuilder app)
34         {
35             // cors
36             app.UseCors("AllowAll");
37 
38             app.UseExceptionMiddleware();
39             // app.UseLogRequestMiddleware();
40             app.UseMvc();
41         }

像獲取token啊,查看api文檔啊就不需要認證了。

5. 註入到Filter

 1     public class NeedAuthAttribute : ActionFilterAttribute
 2     {
 3         private string _name = string.Empty;
 4         private MyUser _user;
 5 
 6         public NeedAuthAttribute(MyUser user, string name = "")
 7         {
 8             _name = name;
 9             _user = user;
10         }
11 
12         public override void OnActionExecuting(ActionExecutingContext context)
13         {
14             this._user.UserName = "aaa";
15         }
16     }

這裡我創建的是個帶字元串參數的類,因為考慮到這個Filter有可能會被覆用,比如限制某個介面只能被某種用戶訪問, 這個字元串便可以存某種用戶的標識。

Filter中還可以註入資料庫訪問的類,這樣我們便可以到資料庫中通過token來獲取到相應的用戶信息。

6. 使用Filter

1 [TypeFilter(typeof(NeedAuthAttribute), Arguments = new object[]{ "bbb" }, Order = 1)]
2 public class ValuesController : Controller

這裡使用了TypeFilter,以載入使用了依賴註入的Filter, 並可以設置參數,跟Filter的順序。

預設Filter的順序是 全局設置->Controller->Action, Order預設都為0,我們可以通過設置Order來改變這個順序。

7. 註入到Controller

 1     public class ValuesController : Controller
 2     {
 3         private MyUser _user;
 4 
 5         public ValuesController(MyUser user)
 6         {
 7             _user = user;
 8         }
 9         ...
10     }

註入到Controller的構造函數中,這樣我們就可以在Controller的Action中使用我們自定義的用戶,就能知道到底當前是哪個用戶在調用這個Action。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • C#面向對象編程 什麼是面向對象? 面向對象編程是上個實際六十年代繼面向結構編程之後提出的一個新的編程思想 封裝,繼承,多態 封裝,繼承,多態是面向對象編程的核心: 封裝是實現面向對象程式設計的第一步,封裝就是將數據或函數等集合在一個個的單元中(我們稱之為類)。被封裝的對象通常被稱為抽象數據類型 意 ...
  • c#3種基本的條件判斷語句有1.if 2.if...else... 3.switch 1.5.1if結構 c#中if結構的語法與java完全相同,即 1. if(表達式) { 代碼塊 } 2. if...else...結構如下 if() { 代碼塊1 } else { 代碼塊2 } 3. 多重if結 ...
  • 微軟最近幾年在跨平臺上不斷發力,很多.net程式員也摩拳擦掌,對微軟寄以厚望。就在最近,微軟還推出了asp .net core2.0預覽版。 通過對.net core的簡單嘗試,我發現以往我們開發MVC項目時,是通過新建一個.edmx文件來生成和更新實體模型,但是在core中,微軟去掉了.edmx, ...
  • 問題描述 使用 Windows Server 2012 R2 或 Windows Server 2016系統,發現在安裝 .NET Framework 3.5.1 時報錯,報錯內容如下圖所示。 原因分析 找不到安裝源文件。 解決辦法 您可以使用如下 PowerShell 腳本進行安裝。 從 開始 菜 ...
  • 1、將解壓後的“KindEditor”文件夾複製到項目的根目錄(此KindEditor文件夾已經經過優化) 下載地址為: http://pan.baidu.com/s/1eS1PRii 2、在<head>標簽中引入KindEditor外部樣式表文件和必需的外部js文件。如下所示: <!--引入樣式表 ...
  • Parallel類是對線程的一個抽象。該類位於System.Threading.Tasks名稱空間中,提供了數據和任務並行性。 Paraller類定義了數據並行地For和ForEach的靜態方法,以及任務並行的Invoke的靜態方法。Parallel.For()和Parallel.ForEach() ...
  • 類似相關問題有以下: WCF- restful介面 POST方式調用報錯(遠程伺服器返回錯誤: 400 錯誤的請求) WCF Rest:不使用UriTemplate使用post方式傳參解決HTTP400問題以及參數映射問題 等等! 具體原因參照:原創:轉載請標明出處:http://www.cnblo ...
  • 一、新建一個html頁面,如註冊頁面"Register.htm" 二、新建一js文件,如:reg.js 三、處理ajax請求 方法一:手動拼接json字元串 新建一般處理程式,如:Register.ashx 方法二:使用Json.NET工具來將C#對象轉換json輸出 1、新建信息類“Msg.cs” ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...