对于基本身份验证,我根据Darin Dimitrov的回答中所示的示例实现了一个自定义HttpMessageHandler
:https://stackoverflow.com/a/11536349/270591
代码使用用户名和角色创建GenericPrincipal
类型的实例principal
,然后将此主体设置为线程的当前主体:
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
//...
}
}
这似乎运行得很好,直到我最近添加了一个使用Task
库的自定义MediaTypeFormatter
,如下所示:
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;
}
(我用这种方法从一些示例代码中以ReadFromStreamAsync
中的Task.Factory.StartNew
开始一项任务.这是错误的吗?可能是问题的唯一原因?)
现在,"有时"——对我来说这似乎是随机的——控制器方法中的User
主体不再是我在MessageHandler中设置的主体,即用户名、Authenticated
标志和角色都丢失了.原因似乎是自定义MediaTypeFormatter导致MessageHandler和controller方法之间的线程发生变化.我通过比较MessageHandler和controller方法中Thread.CurrentThread.ManagedThreadId
的值来确认这一点."有时"他们是不同的,然后校长就"迷路了".
我现在寻找了一种替代设置Thread.CurrentPrincipal
的方法,以某种方式将主体从自定义MessageHandler安全地转移到控制器方法,并在this blog post个请求属性中使用:
request.Properties.Add(HttpPropertyKeys.UserPrincipalKey,
new GenericPrincipal(identity, new string[0]));
我想对此进行测试,但在最近的WebApi版本(候选版本和上周的最终版本)中,HttpPropertyKeys
类(位于名称空间System.Web.Http.Hosting
中)似乎不再具有UserPrincipalKey
属性.
我的问题是:如何更改上面的最后一个代码片段,使其与当前的WebAPI版本兼容?或者一般情况下:如何在自定义MessageHandler中设置用户主体,并在控制器方法中可靠地访问它?
Edit
提到here,"HttpPropertyKeys.UserPrincipalKey
……解析成“MS_UserPrincipal”
",所以我试着用:
request.Properties.Add("MS_UserPrincipal",
new GenericPrincipal(identity, new string[0]));
但它并没有像我预期的那样工作:ApiController.User
属性不包含添加到上面Properties
集合中的主体.