哈嘍大家好,這篇文章其實(shí)很早就想寫了,因?yàn)橐恢睍行』锇閱柕?#xff0c;但是我卻始終拿不到好的方案,最近在錄制《eShopOnContainer微服務(wù)架構(gòu)》的視頻,碰巧就看到了微軟官方的代碼中也有這方面的需求,而且和我的需求不謀而合,那我就抄一下吧,當(dāng)然要適當(dāng)?shù)淖鲂┬薷?#xff0c;可見還是要多學(xué)習(xí)一些框架的。
預(yù)告,從這周開始,BCVP開發(fā)者組正式推廣,因?yàn)槲蚁葘懥诉@篇文章,所以我會在本周三的時候推廣第一個項(xiàng)目,感興趣的還是要來喲《BCVP,想真正為社區(qū)做努力的開發(fā)者們》。
先說下問題吧:
我們平時在開發(fā)ASP.NETCore的WebApi的時候,肯定會有權(quán)限相關(guān)的內(nèi)容,特別是在開發(fā)的階段,需要用到聯(lián)合調(diào)試,或者就是模擬測試,那要獲取真實(shí)的數(shù)據(jù),就需要去登錄,我們雖然有Swagger界面為我們省去了打開前端項(xiàng)目的麻煩,但是Swagger也有自身的一些問題:
1、比如登錄,我們需要設(shè)置時間,萬一半個小時有效期內(nèi)沒有成功,我們還得退出并重新登錄一次;
2、Swagger采用的是Js賦值,那我們刷新了以后,這個Token就不見了,我們又得重新點(diǎn)擊登錄,然后輸入到窗口內(nèi);
3、特別是在調(diào)試Ids4項(xiàng)目的時候,還需要把Ids4認(rèn)證平臺的項(xiàng)目也打開,一起運(yùn)行,才能實(shí)現(xiàn)效果。
可以看到為了簡單的調(diào)試一個業(yè)務(wù)的接口,還是很麻煩的,那我想著有沒有一個方案,可以一次配置,長久有效呢?
肯定是有的,而且很簡單,只需要簡單的設(shè)計(jì)一個中間件,就能輕松搞定,來吧,內(nèi)容很簡單,我就不多解釋了,直接1234上步驟。
1、設(shè)計(jì)權(quán)限通過中間件
這個內(nèi)容還是比較清晰的,我先直接寫下代碼:
/// <summary>/// 測試用戶,用來通過鑒權(quán)/// JWT:?userid=8&rolename=AdminTest/// </summary>public class ByPassAuthMidd{private readonly RequestDelegate _next;// 定義變量:當(dāng)前用戶Id,會常駐內(nèi)存。private string _currentUserId;// 同理定義:當(dāng)前角色名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參數(shù)的形式,設(shè)置用戶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信息了,也就相當(dāng)于登錄了。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()),// 其他參數(shù)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>/// 返回相應(yīng)/// </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);}}
相應(yīng)的注釋,我已經(jīng)添加進(jìn)去了,參數(shù)可以任意增加,過期時間任意配置就行,可能第一次看的時候比較不是很清晰,我下邊會介紹如何使用,你就會明白了。
設(shè)計(jì)好中間件,就需要配置下調(diào)用,在Startup中,配置中間件:
// 測試用戶,用來通過鑒權(quán)if (Configuration.GetValue<bool>("AppSettings:UseLoadTest")){app.UseMiddleware<ByPassAuthMidd>();}// 先開啟認(rèn)證app.UseAuthentication();// 然后是授權(quán)中間件app.UseAuthorization();
注意順序,一定要是認(rèn)證和授權(quán)中間件的上邊,只需要簡單想一想就能明白了,先提供登錄,再進(jìn)行權(quán)限判斷嘛。
其他的修改
1、需要配置參數(shù)
這個是肯定的,就是上邊的AppSettings:UseLoadTest,在appsettings.json中配置,特別注意的是,在生產(chǎn)環(huán)境一定要去掉,或者是禁用,不然被人發(fā)現(xiàn)了,得不償失。
2、修改自定義策略處理器
因?yàn)槲覀円呀?jīng)是這種模擬登錄了,就不需要將Header中的令牌給轉(zhuǎn)到Httpcontext上下文了,已經(jīng)是存在了的,那就需要簡單的修改下PermissionHandler.cs:
主要就是這兩點(diǎn),一個是登錄判斷,增加了一個||的驗(yàn)證,是否是測試環(huán)境;
還有一個就是不用result.Principal賦值了,因?yàn)檫@里是空的。
剩下的就沒有什么了,咱們來操作看看。
2、測試效果
首先、開啟中間件服務(wù)
就是在配置文件中,設(shè)置為true:
"UseLoadTest": true
這個時候,你可以測試下加權(quán)的接口,肯定是由401的:
{"status": 401,"success": false,"msg": "很抱歉,您無權(quán)訪問該接口,請確保已經(jīng)登錄!"
}
其次、配置用戶信息
上邊已經(jīng)有了那個路由了,就是"/noauth",剩下的就是傳遞一個參數(shù),我的BlogCore中需要用到一個userid一個rolename,所以直接傳遞過去:
http://localhost:8081/noauth?userid=8&rolename=AdminTest
這個參數(shù)由你的真實(shí)數(shù)據(jù)決定,也可以做調(diào)整,結(jié)果就是這樣的:
User set to 8 and Role set to AdminTest.
最后、發(fā)起接口測試
直接發(fā)送請求,已經(jīng)可以看到效果了
是不是很方便!我們也可以很隨意的修改過期時間,無論你怎么刷新頁面,數(shù)據(jù)都不會丟,有時候你忘了賦值的是什么用戶和角色了,直接訪問:
如果說想重置,就直接訪問接口
這個時候又開始走我們的策略授權(quán)方案了
是不是很簡單,合理使用中間件,能幫助我們處理很多的麻煩,
就這樣啦,打完收工!
總結(jié)
以上是生活随笔為你收集整理的ASP.NETCore小技巧:使用测试用户中间件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。