【.NET Core 3.1】 策略授权中获取权限数据
▼
更多精彩推薦,上午11點到達
▼
隨著項目關注度漸漸升高,目前已經1.2k個star,我的內心反而更加的惶恐了起來,最近也是很有強迫癥,只要有小伙伴反饋項目的問題,就很著急,哪怕一丁點的問題,就需要思考很久,生怕是底層設計的問題,導致項目有不可挽回的后果,那就斷送了整個項目的發展了。
不過目前還好吧,除了數據庫連接偶爾有人反饋說,在異步并發中,會間歇性的出現連接關閉的問題,其他沒有發現什么。當然如果感覺這個ORM不好用,換成EFCore也是一樣的,其他的功能還是很抗的住,無論是DI、Filter、AOP還是授權。
但是就在前兩天,我在優化代碼的時候,為了做壓測,把所有的附加功能都關了,當然緩存AOP也關閉了:
當時是沒有考慮很多,就把代碼提交到了遠程Github,沒想到引發了一次疑案,很湊巧,剛剛提交上去,立刻就有一個小伙伴反應了問題,說報錯了,然后開了一個bug:
具體的錯誤場景是這樣的,其他頁面很正常,怎么刷新都沒事兒,唯獨【權限分配】頁面報錯了:
其實說實話,很久之前有人斷斷續續的問過這個小問題,但是我一直沒有復現出來,所有就沒辦法去修改,這次正好有一個小伙伴遇到了,我當時一想,肯定是他自己修改了什么,導致出錯了,我下載下來測試一下,就知道了。
沒想到真的報錯了,當時瞬間就感覺慌了,代碼邏輯肯定是沒有問題的,畢竟是寫了一年了,也有很多人在使用,那這種幽靈問題是為何,如果一個項目出現幽靈bug,那是很糾心又難受的,所以,我決定讓自己冷靜冷靜,好好的檢測檢測,故事就開始了。
今天不會去講解什么是JWT,什么是授權,什么是自定義復雜策略授權,這些基本概念,可以看我的視頻或者文章,今天主要說說,在復雜策略授權中,遇到的小問題。
01
到底是哪里的問題?
我看了一下錯誤報告,是這樣的:
大概意思就是,通過sqlsugar請求的時候,因為我是策略授權,所以在PermissionHandler中,增加動態從數據庫獲取角色和接口的映射關系,所以現在在請求的時候,報錯reader已經關閉了,不能再重復訪問了,我當時一臉蒙圈。不會是Sqlsugar有問題吧,這要是底層的問題,可就難受了。看著情況應該是重復使用實例對象了,但是我service層用的是autofac注入沒有問題呀,而且也是scoped的。
現在是找到了問題所在,就是我們的策略授權中,使用了
來獲取角色菜單關系的緣故,下邊我們就是根據問題來找方案了。
02
如何解決這個問題?
當時我就思考著,為何之前沒有遇到過,是因為之前我用的是AOP緩存,這樣每次請求,其實請求的是緩存的數據,所以不會出現重復使用數據庫的DataReader,那方案以就出現了,我也是建議小伙伴這么弄的:
這樣確實沒有問題了,畢竟第一次是請求,后邊十分鐘都是在調用的緩存數據,肯定不會出現重復使用,但是這么說,心里沒有底氣呀,感覺自己都不好意思看到這個答案,夜里久久不能寐,繼續研究。
夜里突然想起來一個問題,既然出現了問題,就要從問題根本著手處理,到底為什么會重復調用同一個DataReader?那肯定有一個地方用單例了,但是我的Service層就是Scope呀,繼續研究,發現了問題所在。
我雖然Service是Scope的,但是授權處理器PermissionHandler當時圖省事兒,設置了單例!
所以,這也就是導致了我們的Service是同一個實例了,而且很湊巧的是,Admin項目中的【權限分配】頁里,正好同時發起了兩次請求,就報錯了。
解決方案就是把PermissionHandler的單例注入,改成Scoped注入即可:
03
進一步深入優化。
上邊的改好了以后,我就深入的想了想,在PermissionHandler處理程序中,既然要獲取全部的用戶菜單關系,而且還是單例的,那為啥每次都要請求一次呢?登錄的時候,獲取一次不就行了?
var data = await _roleModulePermissionServices.RoleModuleMaps();我們刪除PermissionHandler中的相關代碼,把他們移動到了登錄頁,獲取token的時候:
var user = await _sysUserInfoServices.Query(d => d.uLoginName == name && d.uLoginPWD == pass);if (user.Count > 0){var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(name, pass);//如果是基于用戶的授權策略,這里要添加用戶;如果是基于角色的授權策略,這里要添加角色var claims = new List<Claim> {new Claim(ClaimTypes.Name, name),new Claim(JwtRegisteredClaimNames.Jti, user.FirstOrDefault().uID.ToString()),new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));// 就是這里!!!var data = await _roleModulePermissionServices.RoleModuleMaps();var list = (from item in datawhere item.IsDeleted == falseorderby item.Idselect new PermissionItem{Url = item.Module?.LinkUrl,Role = item.Role?.Name,}).ToList();_requirement.Permissions = list;var token = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);return new JsonResult(token);}這樣的話,我們登錄的時候,更新一次,然后其他的時候,就不重復獲取了,但是這樣有個小小的問題,就是如果token有效,管理員在后端修改相應的菜單權限的話,就必須重新登錄了,但是也無傷大雅,我已經在代碼中注釋。
那這樣的話,我們就不用把PermissionHandler的依賴注入方式改成Scope了,這樣也會每次都實例化,干脆還是改成單例,畢竟我們不用在授權處理程序中獲取角色菜單關系了。
所以最后我的兩個方案是:
1、在LoginController的登錄api中,獲取
_roleModulePermissionServices.RoleModuleMaps();
同時,注入的方式,改成Singleton;
2、還是在PermissionHandler中獲取角色菜單Map,但是注入的方式一定要是Scope的。
04
打完收工
目前更新已經一天了,沒有發現問題,有一個bug解決了。
????點擊【閱讀原文】查看Blog.Core開源項目地址
總結
以上是生活随笔為你收集整理的【.NET Core 3.1】 策略授权中获取权限数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 Ocelot 匹配路由的方法匹配路
- 下一篇: 使用ASP.NET Core 3.x 构