哈嘍大家好,這篇文章其實很早就想寫了,因為一直會有小伙伴問到,但是我卻始終拿不到好的方案,最近在錄制《eShopOnContainer微服務架構》的視頻,碰巧就看到了微軟官方的代碼中也有這方面的需求,而且和我的需求不謀而合,那我就抄一下吧,當然要適當的做些修改,可見還是要多學習一些框架的。
預告,從這周開始,BCVP開發者組正式推廣,因為我先寫了這篇文章,所以我會在本周三的時候推廣第一個項目,感興趣的還是要來喲《BCVP,想真正為社區做努力的開發者們》。
先說下問題吧:
我們平時在開發ASP.NETCore的WebApi的時候,肯定會有權限相關的內容,特別是在開發的階段,需要用到聯合調試,或者就是模擬測試,那要獲取真實的數據,就需要去登錄,我們雖然有Swagger界面為我們省去了打開前端項目的麻煩,但是Swagger也有自身的一些問題:
1、比如登錄,我們需要設置時間,萬一半個小時有效期內沒有成功,我們還得退出并重新登錄一次;
2、Swagger采用的是Js賦值,那我們刷新了以后,這個Token就不見了,我們又得重新點擊登錄,然后輸入到窗口內;
3、特別是在調試Ids4項目的時候,還需要把Ids4認證平臺的項目也打開,一起運行,才能實現效果。
可以看到為了簡單的調試一個業務的接口,還是很麻煩的,那我想著有沒有一個方案,可以一次配置,長久有效呢?
肯定是有的,而且很簡單,只需要簡單的設計一個中間件,就能輕松搞定,來吧,內容很簡單,我就不多解釋了,直接1234上步驟。
1、設計權限通過中間件
這個內容還是比較清晰的,我先直接寫下代碼:
/// <summary>/// 測試用戶,用來通過鑒權/// JWT:?userid=8&rolename=AdminTest/// </summary>public class ByPassAuthMidd{private readonly RequestDelegate _next;// 定義變量:當前用戶Id,會常駐內存。private string _currentUserId;// 同理定義:當前角色名private string _currentRoleName;public ByPassAuthMidd(RequestDelegate next){_next = next;_currentUserId = null;_currentRoleName = null;}public async Task Invoke(HttpContext context){var path = context.Request.Path;// 請求地址,通過Url參數的形式,設置用戶id和rolenameif (path == "/noauth"){var userid = context.Request.Query["userid"];if (!string.IsNullOrEmpty(userid)){_currentUserId = userid;}var rolename = context.Request.Query["rolename"];if (!string.IsNullOrEmpty(rolename)){_currentRoleName = rolename;}await SendOkResponse(context, $"User set to {_currentUserId} and Role set to {_currentRoleName}.");}// 重置角色信息else if (path == "/noauth/reset"){_currentUserId = null;_currentRoleName = null;await SendOkResponse(context, $"User set to none. Token required for protected endpoints.");}else{var currentUserId = _currentUserId;var currentRoleName = _currentRoleName;// 你也可以通過Header的形式。//var authHeader = context.Request.Headers["Authorization"];//if (authHeader != StringValues.Empty)//{// var header = authHeader.FirstOrDefault();// if (!string.IsNullOrEmpty(header) && header.StartsWith("User ") && header.Length > "User ".Length)// {// currentUserId = header.Substring("User ".Length);// }//}// 如果用戶id和rolename都不為空// 可以配置HttpContext.User信息了,也就相當于登錄了。if (!string.IsNullOrEmpty(currentUserId) && !string.IsNullOrEmpty(currentRoleName)){var user = new ClaimsIdentity(new[] {// 用戶id new Claim("sub", currentUserId),// 用戶名、角色名new Claim("name", "Test user"),new Claim(ClaimTypes.Name, "Test user"),new Claim("role", currentRoleName),new Claim(ClaimTypes.Role, currentRoleName),// 過期時間,兩個:jwt/ids4new Claim ("exp",$"{new DateTimeOffset(DateTime.Now.AddDays(10100)).ToUnixTimeSeconds()}"),new Claim(ClaimTypes.Expiration, DateTime.Now.AddDays(1).ToString()),// 其他參數new Claim("nonce", Guid.NewGuid().ToString()),new Claim("http://schemas.microsoft.com/identity/claims/identityprovider", "ByPassAuthMiddleware"),new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","User"),new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Microsoft")}, "ByPassAuth");context.User = new ClaimsPrincipal(user);}await _next.Invoke(context);}}/// <summary>/// 返回相應/// </summary>/// <param name="context"></param>/// <param name="message"></param>/// <returns></returns>private async Task SendOkResponse(HttpContext context, string message){context.Response.StatusCode = (int)System.Net.HttpStatusCode.OK;context.Response.ContentType = "text/plain";await context.Response.WriteAsync(message);}}
相應的注釋,我已經添加進去了,參數可以任意增加,過期時間任意配置就行,可能第一次看的時候比較不是很清晰,我下邊會介紹如何使用,你就會明白了。
設計好中間件,就需要配置下調用,在Startup中,配置中間件:
// 測試用戶,用來通過鑒權if (Configuration.GetValue<bool>("AppSettings:UseLoadTest")){app.UseMiddleware<ByPassAuthMidd>();}// 先開啟認證app.UseAuthentication();// 然后是授權中間件app.UseAuthorization();
注意順序,一定要是認證和授權中間件的上邊,只需要簡單想一想就能明白了,先提供登錄,再進行權限判斷嘛。
其他的修改
1、需要配置參數
這個是肯定的,就是上邊的AppSettings:UseLoadTest,在appsettings.json中配置,特別注意的是,在生產環境一定要去掉,或者是禁用,不然被人發現了,得不償失。
2、修改自定義策略處理器
因為我們已經是這種模擬登錄了,就不需要將Header中的令牌給轉到Httpcontext上下文了,已經是存在了的,那就需要簡單的修改下PermissionHandler.cs:
主要就是這兩點,一個是登錄判斷,增加了一個||的驗證,是否是測試環境;
還有一個就是不用result.Principal賦值了,因為這里是空的。
剩下的就沒有什么了,咱們來操作看看。
2、測試效果
首先、開啟中間件服務
就是在配置文件中,設置為true:
"UseLoadTest": true
這個時候,你可以測試下加權的接口,肯定是由401的:
{"status": 401,"success": false,"msg": "很抱歉,您無權訪問該接口,請確保已經登錄!"
}
其次、配置用戶信息
上邊已經有了那個路由了,就是"/noauth",剩下的就是傳遞一個參數,我的BlogCore中需要用到一個userid一個rolename,所以直接傳遞過去:
http://localhost:8081/noauth?userid=8&rolename=AdminTest
這個參數由你的真實數據決定,也可以做調整,結果就是這樣的:
User set to 8 and Role set to AdminTest.
最后、發起接口測試
直接發送請求,已經可以看到效果了
是不是很方便!我們也可以很隨意的修改過期時間,無論你怎么刷新頁面,數據都不會丟,有時候你忘了賦值的是什么用戶和角色了,直接訪問:
如果說想重置,就直接訪問接口
這個時候又開始走我們的策略授權方案了
是不是很簡單,合理使用中間件,能幫助我們處理很多的麻煩,
就這樣啦,打完收工!
總結
以上是生活随笔為你收集整理的ASP.NETCore小技巧:使用测试用户中间件的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。