C# 按域隔离signalR hub中的用户
我有一个web应用程序,它是一个单一的IIS安装(这并没有改变),但是有一个动态的子域集合。每个子域都有自己的用户帐户 我遇到的问题是,当我在其上运行signalR时,它将所有子域视为同一个域,因此碰巧具有相同用户名的用户将相互收到消息 这导致域帐户之间出现安全冲突问题 到目前为止,我的最佳猜测解决方案存在不同程度的风险和问题C# 按域隔离signalR hub中的用户,c#,asp.net,iis,signalr-hub,C#,Asp.net,Iis,Signalr Hub,我有一个web应用程序,它是一个单一的IIS安装(这并没有改变),但是有一个动态的子域集合。每个子域都有自己的用户帐户 我遇到的问题是,当我在其上运行signalR时,它将所有子域视为同一个域,因此碰巧具有相同用户名的用户将相互收到消息 这导致域帐户之间出现安全冲突问题 到目前为止,我的最佳猜测解决方案存在不同程度的风险和问题 每个用户获得自己的组,用子域名+用户名构建组名。 列表项这将碰撞风险降至最低,但不会将其删除 为域名使用Guid,并为Guid保留前n个字符,可以进一步降低风险,但现在,
要查看此失败,只需在ASP.NET/SignalR上获取简单的聊天演示,并在本地计算机上的两种不同浏览器(FF和IE用于我的核心测试)下运行它,一个调用http:\localhost,另一个调用http:\yourcomputername。您将需要IIS而不是IIS Express来进行适当的测试。我的2美分:构建您自己的
IUserIdProvider
实现,从那里可以轻松地检查每个请求并跨多个域生成一个唯一的用户id,您将返回该id,这样信号器就可以知道如何正确地将每个请求关联到谁。这将是一个简单而非侵入性的解决方案。您可以查看更多详细信息。我知道这有点晚了,但是我也遇到了这个问题,我已经通过小组解决了这个问题,然而,我的做法是自己实现IHub,然后在调用setClients
时,在我自己的IHubCallerConnectionContext
实现中包装值,然后使用一个键隔离使用现有方法进行的所有调用。下面是该类的示例:
internal class ClientsDatabaseIsolator : IHubCallerConnectionContext<object>
{
private readonly string _database;
private readonly IHubCallerConnectionContext<dynamic> _clients;
public ClientsDatabaseIsolator(string database, IHubCallerConnectionContext<dynamic> clients)
{
if (database == null) throw new ArgumentNullException(nameof(database));
this._database = database;
this._clients = clients;
}
private string PrefixDatabase(string group)
{
return string.Concat(_database, ".", group);
}
public dynamic AllExcept(params string[] excludeConnectionIds)
{
return _clients.Group(_database, excludeConnectionIds);
}
public dynamic Client(string connectionId)
{
return _clients.Client(connectionId);
}
public dynamic Clients(IList<string> connectionIds)
{
return _clients.Clients(connectionIds);
}
public dynamic Group(string groupName, params string[] excludeConnectionIds)
{
return _clients.Group(PrefixDatabase(groupName), excludeConnectionIds);
}
public dynamic Groups(IList<string> groupNames, params string[] excludeConnectionIds)
{
return _clients.Groups(groupNames.Select(PrefixDatabase).ToList(), excludeConnectionIds);
}
public dynamic User(string userId)
{
return _clients.User(userId);
}
public dynamic Users(IList<string> userIds)
{
return _clients.Users(userIds);
}
public dynamic All
{
get { return _clients.Group(_database); }
}
public dynamic OthersInGroup(string groupName)
{
return _clients.OthersInGroup(PrefixDatabase(groupName));
}
public dynamic OthersInGroups(IList<string> groupNames)
{
return _clients.OthersInGroups(groupNames.Select(PrefixDatabase).ToList());
}
public dynamic Caller
{
get { return _clients.Caller; }
}
public dynamic CallerState
{
get { return _clients.CallerState; }
}
public dynamic Others
{
get { return _clients.OthersInGroup(_database); }
}
}
内部类ClientsDatabaseIsolator:IHubCallerConnectionContext
{
私有只读字符串\u数据库;
专用只读IHubCallerConnectionContext\u客户端;
公共客户端DatabaseIsolator(字符串数据库、IHubCallerConnectionContext客户端)
{
如果(database==null)抛出新的ArgumentNullException(nameof(database));
这个._database=数据库;
这._clients=客户;
}
专用字符串前缀数据库(字符串组)
{
返回字符串.Concat(_数据库,“.”,组);
}
公共动态AllExcept(参数字符串[]ExcludeConnectionId)
{
返回_clients.Group(_数据库,ExcludeConnectionId);
}
公共动态客户端(字符串连接ID)
{
返回_clients.Client(connectionId);
}
公共动态客户端(IList ConnectionId)
{
返回_clients.clients(connectionId);
}
公共动态组(字符串组名,参数字符串[]ExcludeConnectionId)
{
返回_clients.Group(PrefixDatabase(groupName),ExcludeConnectionId);
}
公共动态组(IList组名,参数字符串[]ExcludeConnectionId)
{
返回_clients.Groups(groupNames.Select(PrefixDatabase.ToList(),excludeConnectionId);
}
公共动态用户(字符串用户ID)
{
返回_clients.User(userId);
}
公共动态用户(IList用户ID)
{
返回_clients.Users(userid);
}
公共动态所有
{
获取{return _clients.Group(_database);}
}
公共动态OthersInGroup(字符串groupName)
{
返回_clients.OthersInGroup(PrefixDatabase(groupName));
}
公共动态其他组(IList组名)
{
返回_clients.OthersInGroups(groupNames.Select(PrefixDatabase.ToList());
}
公共动态调用者
{
获取{return\u clients.Caller;}
}
公共动态调用者状态
{
获取{return\u clients.CallerState;}
}
公共动态其他
{
获取{return}clients.OthersInGroup(_数据库);}
}
}
然后在OnConnected
中,我将连接添加到\u数据库
组
现在,在我的中心,当我调用
Clients.All.Send(“message”)
时,实际上只会将消息发送到创建ClientsDatabaseIsolator
时指定的组,这就像调用Clients.group(database).Send(“message”)
那样,你就不必考虑它了。我不确定这是否是最好的解决方案,但它对我们有效 我最终取消了这个项目。显然,服务器上存在的集线器正在扼杀我们的SSRS查看器的性能。虽然我会在有时间的时候重新解释这一点。我最近还意识到,如果使用我的实现,在正常使用组时会出现问题。例如,如果您加入“test”组(如下所示:Groups.Add(Context.ConnectionId),则