如何在自定義 WebAPI HttpMessageHandler 中安全地設置使用者主體?
對於基本身份驗證,我已經
HttpMessageHandler根據 Darin Dimitrov 的回答中顯示的範例實現了自定義:https ://stackoverflow.com/a/11536349/270591程式碼創建一個具有使用者名和角色
principal的類型實例,GenericPrincipal然後將此主體設置為執行緒的目前主體:Thread.CurrentPrincipal = principal;稍後在
ApiController方法中,可以通過訪問控制器User屬性來讀取主體:public class ValuesController : ApiController { public void Post(TestModel model) { var user = User; // this should be the principal set in the handler //... } }這似乎工作正常,直到我最近添加了一個
MediaTypeFormatter使用該Task庫的自定義,如下所示:public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) { var task = Task.Factory.StartNew(() => { // some formatting happens and finally a TestModel is returned, // simulated here by just an empty model return (object)new TestModel(); }); return task; }
Task.Factory.StartNew(我有這種方法可以從一些範常式式碼中開始一項任務ReadFromStreamAsync。這是錯誤的,也許是問題的唯一原因?)現在,“有時”——對我來說似乎是隨機的——
User控制器方法中的主體不再是我在 MessageHandler 中設置的主體,即使用者名、Authenticated標誌和角色都失去了。原因似乎是自定義 MediaTypeFormatter 導致 MessageHandler 和控制器方法之間的執行緒發生變化。我已經通過比較Thread.CurrentThread.ManagedThreadIdMessageHandler 和控制器方法中的值來確認這一點。“有時”它們是不同的,然後校長就“迷失了”。我現在正在尋找一種替代方法來設置
Thread.CurrentPrincipal以某種方式將主體從自定義 MessageHandler 安全地傳輸到控制器方法,並且在此部落格文章中使用了請求屬性:request.Properties.Add(HttpPropertyKeys.UserPrincipalKey, new GenericPrincipal(identity, new string[0]));我想對此進行測試,但似乎
HttpPropertyKeys該類(位於 namespace 中)在最近的 WebApi 版本(上週的候選版本和最終版本System.Web.Http.Hosting)中不再具有屬性。UserPrincipalKey我的問題是:如何更改上面的最後一個程式碼片段,以便與目前的 WebAPI 版本一起使用?或者一般來說:如何在自定義 MessageHandler 中設置使用者主體並在控制器方法中可靠地訪問它?
編輯
這裡提到“
HttpPropertyKeys.UserPrincipalKey…解析為“MS_UserPrincipal””,所以我嘗試使用:request.Properties.Add("MS_UserPrincipal", new GenericPrincipal(identity, new string[0]));但它並沒有像我預期的那樣工作:該
ApiController.User屬性不包含添加到Properties上面集合中的主體。
這裡提到了在新執行緒上失去本金的問題:
<http://leastprivilege.com/2012/06/25/important-setting-the-client-principal-in-asp-net-web-api/>
重要提示:在 ASP.NET Web API 中設置客戶端主體
由於一些不幸的機制深埋在 ASP.NET 中,在 Web API 虛擬主機中設置 Thread.CurrentPrincipal 是不夠的。
在 ASP.NET 中託管時,Thread.CurrentPrincipal 可能會在創建新執行緒時被 HttpContext.Current.User 覆蓋。這意味著您必須線上程和 HTTP 上下文中設置主體。
在這裡:http ://aspnetwebstack.codeplex.com/workitem/264
今天,如果您使用自定義消息處理程序在 Web 託管方案中執行身份驗證,則需要為使用者主體設置以下兩項。
IPrincipal principal = new GenericPrincipal( new GenericIdentity("myuser"), new string[] { "myrole" }); Thread.CurrentPrincipal = principal; HttpContext.Current.User = principal;我已將最後一行
HttpContext.Current.User = principal(需要using System.Web;)添加到消息處理程序User中,並且ApiController現在確實始終具有正確的主體,即使執行緒由於 MediaTypeFormatter 中的任務而發生更改。編輯
HttpContext只是要強調一點:僅當 WebApi 託管在 ASP.NET/IIS 中時,才需要設置目前使用者的主體。對於自託管,它不是必需的(也不可能,因為HttpContext它是一個 ASP.NET 構造,並且在自託管時不存在)。