在从Web访问的自托管SignalR服务器中实现授权

在从Web访问的自托管SignalR服务器中实现授权,signalr,signalr-hub,signalr.client,Signalr,Signalr Hub,Signalr.client,我正在寻找一些关于如何在自托管(非IIS)环境(从Web应用程序调用)中运行的后端服务上为SignalR实现授权安全性的指导。后端应用程序基本上是一个监视器,它将信号器事件发回基于HTML的客户端。这一切都很好(实际上非常好) 但是,我们需要限制通过身份验证的用户从网站访问服务器。因此,基本上,如果用户在网站上经过身份验证,我们需要以某种方式在后端应用程序中获取凭据(用户名足够)和验证状态,以决定是否允许连接,从而避免未经授权的访问 有人能指出一些策略或模式来实现这种身份验证转发吗?Signal

我正在寻找一些关于如何在自托管(非IIS)环境(从Web应用程序调用)中运行的后端服务上为SignalR实现授权安全性的指导。后端应用程序基本上是一个监视器,它将信号器事件发回基于HTML的客户端。这一切都很好(实际上非常好)

但是,我们需要限制通过身份验证的用户从网站访问服务器。因此,基本上,如果用户在网站上经过身份验证,我们需要以某种方式在后端应用程序中获取凭据(用户名足够)和验证状态,以决定是否允许连接,从而避免未经授权的访问


有人能指出一些策略或模式来实现这种身份验证转发吗?

Signal不提供任何额外的身份验证功能。相反,它被设计为与应用程序的身份验证机制一起工作

集线器

您应该像平常一样进行身份验证,然后使用SignalR提供的Authorize属性在集线器上强制执行身份验证的结果

Authorize属性可以应用于整个中心或中心中的特定方法。一些例子:

  • [授权]–仅限经过身份验证的用户
  • [Authorize(Roles=“Admin,Manager”)]–仅限指定.NET角色中经过身份验证的用户
  • [Authorize(Users=“user1,user2”)]–仅具有指定用户名的经过身份验证的用户
通过在应用程序启动方法中添加以下方法,还可以要求所有集线器都需要身份验证:

GlobalHost.HubPipeline.RequireAuthentication()

持久连接

您可以在请求中使用user对象来查看用户是否经过身份验证:

request.User.IsAuthenticated


我在这里遇到了类似的问题,因为在我的web应用程序中,我使用了一个简单的cookie身份验证系统,该系统使用AoP风格的方法来检查任何具有属性的控制器,然后将获取当前上下文(可以是来自静态HttpContext.current或来自目标调用对象,具体取决于拦截器的类型)然后验证cookie是否存在,它是否包含正确的数据,最后使用db或缓存等验证令牌

无论如何,这种方法也可以用于Signalr,尽管它有点冗长,并且您正在使用依赖项注入。基本上,您可以使用所需的属性包装集线器调用,然后设置DI/IoC配置以拦截这些调用,然后在拦截器中获取集线器实例并从请求中获取cookie(或自定义身份验证机制),验证其是否都有效,如果不有效,则抛出一个
新的HttpException(“403”,“Not authenticated”);
这应该会在用户访问中心方法之前将其踢出并返回,这样您就可以将逻辑放在一个位置(您的拦截器或拦截器使用的类),然后使用您的属性包装任何需要使用此身份验证的方法

我使用Ninject和拦截扩展,但现在大多数主要的DI框架都有某种形式的IoC插件/扩展,如Autofac、Windsor、Spring等

如果您不愿意在当前项目中引入DI和/或AOP,那么您可以创建一个包含身份验证逻辑的自定义集线器实例,然后在集线器中使用该实例,这样您仍然可以从要保护的每个集线器方法中手动调用一些身份验证逻辑,但它的代码较少,所以类似于:

public class AuthorisableHub : Hub
{
    private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
    {
        // Get your token from the querystring or cookie etc
    }

    private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
    {
        // Perform some validation, be it simple or db based and return result
    }

    protected void PerformUserAuthentication()
    {
        var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
        var isRequestValid = IsAuthenticationTokenValid(token);

        if(!isRequestValid)
        { throw new HttpException(403, "<Some forbidden message here>"); }
    }
}

public class MyFancyPantsHub : AuthorisableHub
{
    public void TellAllClientsSomethingSecret(ISecret secret)
    {
        PerformUserAuthentication();

        // Do stuff with the secret as it should have bombed the user out
        // before it reaches here if working correctly
    }
}
公共类授权集线器:集线器
{
私有ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(请求请求)//可能是特定于信号器的请求对象
{
//从查询字符串或cookie等获取您的令牌
}
私有bool IsAuthenticationTokenValid(ISomeAuthenticationToken令牌)
{
//执行一些验证,无论是简单的还是基于数据库的,并返回结果
}
受保护的无效性能验证()
{
var token=GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid=IsAuthenticationTokenValid(令牌);
如果(!isRequestValid)
{抛出新的HttpException(403,“”;}
}
}
公共类MyFancyPantsHub:授权中心
{
公开无效告知所有客户保密(ISecret秘密)
{
执行身份验证();
//用这个秘密做一些事情,因为它应该把用户炸出来
//在它到达这里之前,如果工作正常
}
}
它不是完美的,但会起作用(我认为),而且我确信我曾经在某个地方读到过集线器是为每个请求新实例化的,如果这确实是真的,那么如果您想将身份验证应用于集线器中的每个操作,您可以将此逻辑放在构造函数中


希望这对您有所帮助,或者给您一些想法……我有兴趣知道您最终是如何解决的。

我通过查询字符串(即$.connection.hub.qs)将生成的用户令牌与每个信号器请求一起传递,从而实现了基于令牌的安全性.客户端生成交叉引用用户的密钥,在服务器上,我提取令牌,然后从交叉引用加载用户。这是可行的,但非常难看,而且除了调用ValidateToken()之外,我无法清楚地执行安全性方法引发错误。对此有任何更新吗?您找到更好的方法了吗?我遇到了完全相同的情况。我没有使用ASP.NET托管此SignalR服务,因此我认为这不起作用,因为没有ASP.NET安全性或身份检查。我知道SignalR不提供内置身份验证,这很好。什么我想知道如何在应用程序之间传递安全上下文,然后如何传递