Chr*_*ris 13 c# signalr asp.net-mvc-5
问题:如何管理匿名用户,以便在Hub发出响应时,单个浏览器中的多个选项卡都会更新?
方案如下:
我想将SignalR集成到一个项目中,以便匿名用户可以与运营商进行实时聊天.显然,使用iIdentity进行身份验证的用户通过Client.User(username)命令进行映射.但目前一位匿名用户正在浏览site.com/tools和site.com/notTools我无法仅使用connectionID向所有标签发送消息.只有一个选项卡收集响应.
我尝试过使用IWC补丁,但该工具不考虑将聊天信息保存到数据库中,我认为通过ajax传递变量并不是一种读取/写入数据库的安全方法.
我还查看了以下内容:管理匿名用户的SignalR连接
然而,创建一个这样的基础并使用会话似乎不如Owin安全.
我有想法通过每次用户连接时创建一个虚假帐户来使用client.user(),并在断开连接时将其删除.但我宁愿不用垃圾帐户填充我的aspnetusers数据库上下文似乎没必要.
是否可以使用UserHandler.ConnectedIds.Add(Context.ConnectionId);也映射假用户名?我不知所措.
使用iUserId提供商是否有意义?
public interface IUserIdProvider
{
string GetUserId(IRequest request);
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个数据库,将IP地址存储到connectionID和单个用户名?
数据库:
用户:使用FK连接ID
|userid|username|IP |connectionIDs|
| 1 | user1 |127.0.0.1| 1 |
| 2 | user2 |127.0.0.2| 2 |
Run Code Online (Sandbox Code Playgroud)
connectionIDs:
|connectionID|SignalRID|connectionIDs|
| 1 | xx.x.x.x| 1 |
| 2 | xx.xxx.x| 2 |
| 3 | xx.xxxxx| 2 |
| 4 | xxxxx.xx| 2 |
Run Code Online (Sandbox Code Playgroud)
然后可能在连接周围编写逻辑?
public override Task OnConnected()
{
if(Context.Identity.UserName != null){
//add a connection based on the currently logged in user.
}
else{
///save new user to database?
}
}
Run Code Online (Sandbox Code Playgroud)
但问题仍然是如何在websocket上发送命令时如何处理多个标签?
更新 为了清楚起见,我的目的是创建一个实时聊天/支持工具,允许在浏览器中始终进行匿名访问.
客户想要类似http://www.livechatinc.com的东西
我已经创建了一个javascript插件,可以从集线器发送和接收,无论它在哪个域上.(我的客户有多站点)这个难题的缺失部分是最简单的,管理匿名用户以允许多标签对话.
我没有遵循虚假用户帐户的想法(不知道它是否有效),但会开发一种替代方案.
目标可以通过所有浏览器选项卡共享的ChatSessionId cookie并创建名为此ChatSessionId的组来实现.
我从asp.net/signalr获取了基本的聊天教程,并添加了允许来自同一用户的多个标签聊天的功能.
1)在"聊天"操作中分配聊天会话ID以识别用户,因为我们没有用户凭证:
public ActionResult Chat()
{
ChatSessionHelper.SetChatSessionCookie();
return View();
}
Run Code Online (Sandbox Code Playgroud)
2)进入聊天页面时订阅聊天会话
客户端
$.connection.hub.start()
.then(function(){chat.server.joinChatSession();})
.done(function() {
...
Run Code Online (Sandbox Code Playgroud)
服务器端(集线器)
public Task JoinChatSession()
{
//get user SessionId to allow use multiple tabs
var sessionId = ChatSessionHelper.GetChatSessionId();
if (string.IsNullOrEmpty(sessionId)) throw new InvalidOperationException("No chat session id");
return Groups.Add(Context.ConnectionId, sessionId);
}
Run Code Online (Sandbox Code Playgroud)
3)向用户的聊天会话广播消息
public void Send(string message)
{
//get user chat session id
var sessionId = ChatSessionHelper.GetChatSessionId();
if (string.IsNullOrEmpty(sessionId)) throw new InvalidOperationException("No chat session id");
//now message will appear in all tabs
Clients.Group(sessionId).addNewMessageToPage(message);
}
Run Code Online (Sandbox Code Playgroud)
最后,(简单)ChatSessionHelper类
public static class ChatSessionHelper
{
public static void SetChatSessionCookie()
{
var context = HttpContext.Current;
HttpCookie cookie = context.Request.Cookies.Get("Session") ?? new HttpCookie("Session", GenerateChatSessionId());
context.Response.Cookies.Add(cookie);
}
public static string GetChatSessionId()
{
return HttpContext.Current.Request.Cookies.Get("Session")?.Value;
}
public static string GenerateChatSessionId()
{
return Guid.NewGuid().ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
一种广泛采用的解决方案是让用户在 onConnected 上使用他的某种 id 和连接进行注册。
public override Task OnConnected()
{
Clients.Caller.Register();
return base.OnConnected();
}
Run Code Online (Sandbox Code Playgroud)
然后用户返回带有某种您自己的 id 逻辑的调用
来自客户注册方法
public void Register(Guid userId)
{
s_ConnectionCache.Add(userId, Guid.Parse(Context.ConnectionId));
}
Run Code Online (Sandbox Code Playgroud)
并且将用户 ID 保存在静态字典中(注意锁,因为您需要它是线程安全的;
static readonly IConnectionCache s_ConnectionCache = new ConnectionsCache();
Run Code Online (Sandbox Code Playgroud)
这里
public class ConnectionsCache :IConnectionCache
{
private readonly Dictionary<Guid, UserConnections> m_UserConnections = new Dictionary<Guid, UserConnections>();
private readonly Dictionary<Guid,Guid> m_ConnectionsToUsersMapping = new Dictionary<Guid, Guid>();
readonly object m_UserLock = new object();
readonly object m_ConnectionLock = new object();
#region Public
public UserConnections this[Guid index]
=>
m_UserConnections.ContainsKey(index)
?m_UserConnections[index]:new UserConnections();
public void Add(Guid userId, Guid connectionId)
{
lock (m_UserLock)
{
if (m_UserConnections.ContainsKey(userId))
{
if (!m_UserConnections[userId].Contains(connectionId))
{
m_UserConnections[userId].Add(connectionId);
}
}
else
{
m_UserConnections.Add(userId, new UserConnections() {connectionId});
}
}
lock (m_ConnectionLock)
{
if (m_ConnectionsToUsersMapping.ContainsKey(connectionId))
{
m_ConnectionsToUsersMapping[connectionId] = userId;
}
else
{
m_ConnectionsToUsersMapping.Add(connectionId, userId);
}
}
}
public void Remove(Guid connectionId)
{
lock (m_ConnectionLock)
{
if (!m_ConnectionsToUsersMapping.ContainsKey(connectionId))
{
return;
}
var userId = m_ConnectionsToUsersMapping[connectionId];
m_ConnectionsToUsersMapping.Remove(connectionId);
m_UserConnections[userId].Remove(connectionId);
}
}
Run Code Online (Sandbox Code Playgroud)
从 Android 应用程序调用 Register 的示例
mChatHub.invoke("Register", PrefUtils.MY_USER_ID).get();
Run Code Online (Sandbox Code Playgroud)
对于 JS 来说是一样的
chat.client.register = function () {
chat.server.register(SOME_USER_ID);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1292 次 |
| 最近记录: |