asp.net - 如何在自定义 WebAPI HttpMessageHandler 中安全地设置用户主体?

标签 asp.net .net asp.net-mvc security asp.net-web-api

对于基本身份验证,我已经实现了自定义 HttpMessageHandler基于 Darin Dimitrov 的答案中显示的示例:https://stackoverflow.com/a/11536349/270591

代码创建一个实例principal类型 GenericPrincipal包含用户名和角色,然后将此主体设置为线程的当前主体:

Thread.CurrentPrincipal = principal;

稍后在 ApiController方法主体可以通过访问 Controller 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 in ReadFromStreamAsync 启动任务。这是错误的,也许是问题的唯一原因?)

现在,“有时” - 对我来说它似乎是随机的 - User Controller 方法中的主体不再是我在 MessageHandler 中设置的主体,即用户名 Authenticated旗帜和角色全部丢失。原因似乎是自定义 MediaTypeFormatter 导致 MessageHandler 和 Controller 方法之间的线程发生变化。我通过比较 Thread.CurrentThread.ManagedThreadId 的值证实了这一点在 MessageHandler 和 Controller 方法中。 “有时”它们是不同的,然后校长就“迷失”了。

我现在正在寻找设置 Thread.CurrentPrincipal 的替代方案以某种方式将主体安全地从自定义 MessageHandler 传输到 Controller 方法并在 this blog post 中使用请求属性:

request.Properties.Add(HttpPropertyKeys.UserPrincipalKey,
    new GenericPrincipal(identity, new string[0]));

我想测试一下,但似乎HttpPropertyKeys类(位于命名空间 System.Web.Http.Hosting 中)没有 UserPrincipalKey最近的 WebApi 版本(候选版本和上周的最终版本)中不再包含此属性。

我的问题是:如何更改上面的最后一个代码片段,以便它适用于当前的 WebAPI 版本?或者一般来说:如何在自定义 MessageHandler 中设置用户主体并在 Controller 方法中可靠地访问它?

编辑

提到hereHttpPropertyKeys.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/

Important: Setting the Client Principal in ASP.NET Web API

Due to some unfortunate mechanisms buried deep in ASP.NET, setting Thread.CurrentPrincipal in Web API web hosting is not enough.

When hosting in ASP.NET, Thread.CurrentPrincipal might get overridden with HttpContext.Current.User when creating new threads. This means you have to set the principal on both the thread and the HTTP context.

这里:http://aspnetwebstack.codeplex.com/workitem/264

Today, you will need to set both of the following for user principal if you use a custom message handler to perform authentication in the web hosted scenario.

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 中的 code> 属性现在始终具有正确的主体,即使线程由于 MediaTypeFormatter 中的任务而发生更改也是如此。

编辑

强调一下:仅当 WebApi 托管在 ASP.NET/IIS 中时,才需要设置 HttpContext 当前用户的主体。对于自托管来说,没有必要(也不可能,因为 HttpContext 是一个 ASP.NET 构造,并且在自托管时不存在)。

关于asp.net - 如何在自定义 WebAPI HttpMessageHandler 中安全地设置用户主体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12028604/

相关文章:

c# - Windows 窗体中的数据注释支持

c# - 如何在asp.net mvc 3中制作不同的name属性名称?

ASP.NET MVC Head Verb 和 Selenium RC

c# - 发送格式化电子邮件 Asp.Net

c# - 适用于 .NET 开发的 Windows 7

c# - 以线程安全的方式使用增量编号更新文件

.net - $.connection.hub.start().done() 上出现错误 500

javascript - 我们如何在 SignalR 中执行基于 OWIN oAuth Bearer token 的身份验证和授权?

c# - EntityFramework 可以使用提供程序 System.Data.SqlClient 的标准连接字符串吗?

c# - 如何使用 HTMLAgility 包在另一个网页上发布数据?