Подтвердить что ты не робот

SignalR С# MVC Отображение анонимного пользователя с идентификатором клиента

Вопрос: Как мне управлять анонимными пользователями, чтобы обновить несколько вкладок в одном браузере, когда концентратор отправляет ответ?

Сценарий выглядит следующим образом:

Я хотел бы интегрировать SignalR в проект, чтобы анонимные пользователи могли общаться в чате с операторами. Очевидно, что пользователь, прошедший аутентификацию с помощью iIdentity, отображается с помощью команды Client.User(username). Но в настоящее время говорят, что анонимный пользователь просматривает site.com/tools и site.com/notTools. Я не могу отправлять сообщения на все вкладки только с идентификатором соединения. Ответ.

Я попытался использовать патч IWC, но этот инструмент не учитывает сохранение информации о чатах в базе данных, и я думаю, что передача переменных через ajax не является безопасным способом чтения/записи в базу данных.

Я также рассмотрел следующее: Управление соединениями SignalR для анонимного пользователя

Однако создание такой базы, как эта, и использование сеансов, кажется менее надежным, чем Owin.

У меня возникла идея использовать client.user(), создавая ложную учетную запись каждый раз, когда пользователь подключается и удаляет ее при отключении. Но я предпочел бы не заполнять мой контекст db-контекста с помощью мусорных учетных записей, это кажется ненужным.

Можно ли использовать UserHandler.ConnectedIds.Add(Context.ConnectionId);, чтобы также отобразить поддельное имя пользователя? Я в недоумении.

Имеет ли смысл использовать iUserId провайдера?

public interface IUserIdProvider
{
    string GetUserId(IRequest request);
}

Затем создайте базу данных, в которой хранятся IP-адреса для идентификаторов соединений и одиночных имен пользователей?

базы данных:

Пользователи: с идентификаторами FK для подключения

|userid|username|IP       |connectionIDs|
|   1  | user1  |127.0.0.1|  1          |
|   2  | user2  |127.0.0.2|  2          |

connectionIDs:

|connectionID|SignalRID|connectionIDs|
|      1     | xx.x.x.x|     1       |
|      2     | xx.xxx.x|     2       |
|      3     | xx.xxxxx|     2       |
|      4     | xxxxx.xx|     2       |

Затем возможно написать логику вокруг соединения?

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?
     } 
  }

но остается вопрос, как я могу обрабатывать несколько вкладок с этим при отправке команды на веб-сайт?

Обновление Чтобы быть ясным, я намерен создать интерактивный чат/инструмент поддержки, который позволяет в анонимном доступе браузера в любое время.

Клиент хочет что-то похожее на http://www.livechatinc.com

Я уже создал плагин javascript, который отправляет и получает от концентратора, независимо от того, в каком домене он включен. (у моего клиента многосайты) недостающая часть головоломки является самой простой, позволяющей анонимным пользователям разрешать многозадачные разговоры.

4b9b3361

Ответ 1

широко принятое решение состоит в том, чтобы заставить пользователя зарегистрироваться с его каким-либо идентификатором с подключением обратно на onConnected.

 public override Task OnConnected()
        {
            Clients.Caller.Register();


            return base.OnConnected();
        }

а пользователь возвращает с вызовом с какой-то своей логикой id

из метода регистрации клиентов

 public void Register(Guid userId)
    {
        s_ConnectionCache.Add(userId, Guid.Parse(Context.ConnectionId));
    }

и вы сохраняете идентификаторы пользователя в статическом словаре (позаботьтесь о блокировках, так как вам нужно, чтобы он был потокобезопасным;

static readonly IConnectionCache s_ConnectionCache = new ConnectionsCache();

здесь

 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);
        }



    }

образец вызова для регистрации формы приложения для Android

 mChatHub.invoke("Register", PrefUtils.MY_USER_ID).get();

для JS это будет своего рода

 chat.client.register = function () {
    chat.server.register(SOME_USER_ID);
}

Ответ 2

Я не следую идее ложной учетной записи пользователя (не знаю, работает ли она), но разработает альтернативу.

Цель может быть достигнута с помощью cookie ChatSessionId, разделяемого всеми вкладками браузера, и создания групп, названных как этот ChatSessionId.

Я взял основной учебник по чату из asp.net/signalr и добавил функциональность, чтобы разрешить чат с нескольких вкладок в качестве одного и того же пользователя.

1) Назначьте идентификатор сеанса чата в действии "Чат", чтобы идентифицировать пользователя, поскольку у нас нет учетных данных пользователя:

    public ActionResult Chat()
    {
        ChatSessionHelper.SetChatSessionCookie();
        return View();
    }

2) Подпишитесь на чат-сеанс при входе на страницу чата

клиентская сторона

    $.connection.hub.start()
        .then(function(){chat.server.joinChatSession();})
        .done(function() {
           ...

серверная сторона (концентратор)

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);
}

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);
}

Наконец, класс (простой) 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();
    }
}