使用SignalR注入IPrincipal

6
我正在尝试将 IPrincipal 注入到我的 SignalR Hub 构造函数中。 我已经看到并尝试了 "Selective IPrincipal Injection via StructureMap with SignalR" 中的解决方案,但不幸的是这似乎对于 SignalR 2.x 不起作用。
在我的调试中,我发现 有时候,我的 Hub 构造函数被调用并带有我的 OWIN 中间件。当出现这种情况时,Thread.CurrentPrincipal 是正确的值。此外(令人惊讶的是),HttpContext.Current 也不为 null。我以为在 SignalR 中它总是 null,虽然我没有尝试使用它,但我只是观察。好像这些可行的调用来自调用堆栈中的管道。
其他时候,调用似乎来自线程池。在这些实例中,Thread.CurrentPrincipal 是一个 GenericPrincipalHttpContext.Current 为 null(再次只是观察),而且我似乎无法以静态方式获取主体。然而,在 Hub 内部,this.Context.User 属性确实具有正确的主体。
还有什么其他方法可以使我以静态方式获取主体,以便我可以将其注入到 Hub 构造函数中?

为了解决这个问题,我创建了一个WebAPI:用户可以使用我的API加入组或发送消息。在这个API中,我可以检查身份/角色。 - Guillaume
@Guillaume 这怎么解决SignalR的问题? - David Pfeffer
那并不能真正解决你的问题,这就是我没有发布答案的原因。这只是一个解决方案,可以在用户发出所有传入操作时获取IPrincipal。控制器充当客户端和中心之间的代理。对于实时(游戏等)可能不太好。 - Guillaume
1
我认为你不想在线程池线程上设置IPrincipal。在其他情况下这样做是错误的。 - Brannon
3个回答

2
如果我理解正确你想要做什么……你应该构建自己的授权属性,将自定义主体放入特殊的Owin变量中,然后可以在hub内部通过Context.User访问它。
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
    {
        //put our custom user-principal into a magic "server.User" Owin variable
        request.Environment["server.User"] = new MyCustomPrincipal(); //<!-THIS!

        return base.AuthorizeHubConnection(hubDescriptor, request);
    }
}

然后将此属性应用于您的Hub。

如果您想了解更多信息,请查看我关于此的博客这里,其中包含更多的代码示例。


2
预计在 SignalR Hubs 激活时,HttpContext.CurrentThread.CurrentPrincipal 有时会被设置,但并非总是如此。这是因为激活线程通常使用 ASP.NET 的SynchronizationContext 运行。但也有一些情况不是这样的,例如当一个 Hub 被激活以处理 WebSocket 消息或不完整的 OnDisconnected 事件时。简而言之,有时这些静态变量可能存在,但您不能依赖它。
我不知道任何一种可靠地静态获取 IPrincipal 的方法。在您的 Hub 中使用 Context.User 有什么问题吗?

2
Context.User 依赖于更紧密的耦合到 SignalR hubs 框架,这降低了我在 SignalR 和 Web API 之间共享代码的能力,例如,没有包装函数就无法实现。 - David Pfeffer

0

我曾试图解决同样的问题,并找到了设置用户身份的解决方案。

我的应用程序受到SAML保护,客户端应用程序将"SAML"令牌作为标头的一部分发送。我们编写了Asp.net模块来验证令牌并准备用户的身份,并向响应标头添加值。

我创建了OwinStartup类,并使用以下代码添加了自己的请求处理器。我已经测试了这段代码的Longpolling功能,并且运行良好。但我不确定它在"WebScoket"中如何工作。

 public void Configuration(IAppBuilder app)
    {
        // Any connection or hub wire up and configuration should go here           
        try
        {
            app.Use(SetMyPrincipalObject);
        }
    }

  private Task SetMyPrincipalObject(IOwinContext arg1, Func<Task> arg2)
    {
        //var p = "Process response";//Process Response Header here and //create identity
        //arg1.Request.User = p;
        //return arg2.Invoke();
    }

这完全没有回答问题。 - David Pfeffer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接