SignalR-(IUserIdProvider) * NEW 2.0.0 *을 사용하여 특정 사용자에게 메시지 보내기


101

최신 버전의 Asp.Net SignalR에서는 "IUserIdProvider"인터페이스를 사용하여 특정 사용자에게 메시지를 보내는 새로운 방법이 추가되었습니다.

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

public class MyHub : Hub
{
   public void Send(string userId, string message)
   {
      Clients.User(userId).send(message);
   }
}

내 질문은 내가 누구에게 내 메시지를 보내는 지 어떻게 알 수 있습니까? 이 새로운 방법에 대한 설명은 매우 피상적입니다. 그리고이 버그가 포함 된 SignalR 2.0.0의 성명서 초안은 컴파일되지 않습니다. 이 기능을 구현 한 사람이 있습니까?

추가 정보 : http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider

포옹.


1
SignalR을 사용한 인증 및 권한 부여를 살펴 봐야합니다. UserId는 IPrincipal 공급자의 일부가됩니다.
Gjohn

답변:


153

SignalR은 각 연결에 대한 ConnectionId를 제공합니다. 어떤 연결이 누구 (사용자)에게 속하는지 확인하려면 연결과 사용자 간의 매핑을 만들어야합니다. 이는 애플리케이션에서 사용자를 식별하는 방법에 따라 다릅니다.

SignalR 2.0에서는 IPrincipal.Identity.NameASP.NET 인증 중에 설정된 로그인 사용자 식별자 인 inbuilt를 사용하여 수행됩니다 .

그러나 Identity.Name을 사용하는 대신 다른 식별자를 사용하여 사용자와의 연결을 매핑해야 할 수 있습니다. 이를 위해이 새 공급자를 사용자 지정 구현과 함께 사용하여 사용자를 연결에 매핑 할 수 있습니다.

IUserIdProvider를 사용하여 SignalR 사용자를 연결에 매핑하는 예

응용 프로그램에서 a userId를 사용하여 각 사용자를 식별 한다고 가정 해 보겠습니다 . 이제 특정 사용자에게 메시지를 보내야합니다. 우리가 userId하고 message있지만, SignalR는 또한 우리의 사용자 ID와 연결 간의 매핑을 알고 있어야합니다.

이를 위해 먼저 다음을 구현하는 새 클래스를 만들어야합니다 IUserIdProvider.

public class CustomUserIdProvider : IUserIdProvider
{
     public string GetUserId(IRequest request)
    {
        // your logic to fetch a user identifier goes here.

        // for example:

        var userId = MyCustomUserClass.FindUserId(request.User.Identity.Name);
        return userId.ToString();
    }
}

두 번째 단계는 SignalR에 CustomUserIdProvider기본 구현 대신 우리를 사용하도록 지시하는 것입니다. 허브 구성을 초기화하는 동안 Startup.cs에서 수행 할 수 있습니다.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var idProvider = new CustomUserIdProvider();

        GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);          

        // Any connection or hub wire up and configuration should go here
        app.MapSignalR();
    }
}

이제 다음 userId과 같이 문서에 언급 된대로 특정 사용자에게 메시지를 보낼 수 있습니다 .

public class MyHub : Hub
{
   public void Send(string userId, string message)
   {
      Clients.User(userId).send(message);
   }
}

도움이 되었기를 바랍니다.


안녕하세요 친구, 늦은 피드백에 대해 죄송합니다! 하지만 CustomUserIdProvider를 생성하는 Id에 액세스하려고했지만 "OnConnected"메서드는 동일하지 않습니다. 데이터베이스의 사용자에게 어떻게 링크합니까? 감사합니다!
Igor

7
MyCustomUserClass 란 무엇입니까?
Danny Bullis

2
"MyCustomUserClass"는 FindUserId 메서드를 포함하는 사용자 지정 사용자 클래스 일 수 있습니다. 이것은 단지 예입니다. UserId를 반환하는 모든 클래스의 메서드를 여기에서 사용할 수 있습니다.
Sumant

5
감사합니다 @Sumant, 내 문제는 내가 베어러 토큰으로 OAuth 2를 구현 한 Web API 프로젝트에 있었기 때문에 쿼리 문자열에서 베어러 토큰을 가져올 수 없기 때문에 논리를 구현해야했습니다. 해당 초기 시그널 러 연결 요청의 헤더. request.User.Identity.Name을 사용할 수 없습니다
xinunix

1
@Sumant 나는 이미 그것을 해결했습니다. 문제는 app.MapSignalR();인증 전에 global.asax를 넣었다는 것입니다 .
Mr. Robot

38

여기 시작합니다 .. 제안 / 개선 사항을 엽니 다.

섬기는 사람

public class ChatHub : Hub
{
    public void SendChatMessage(string who, string message)
    {
        string name = Context.User.Identity.Name;
        Clients.Group(name).addChatMessage(name, message);
        Clients.Group("2@2.com").addChatMessage(name, message);
    }

    public override Task OnConnected()
    {
        string name = Context.User.Identity.Name;
        Groups.Add(Context.ConnectionId, name);

        return base.OnConnected();
    }
}

자바 스크립트

( 위의 서버 코드에있는 방법 addChatMessagesendChatMessage방법에 주목하십시오 )

    $(function () {
    // Declare a proxy to reference the hub.
    var chat = $.connection.chatHub;
    // Create a function that the hub can call to broadcast messages.
    chat.client.addChatMessage = function (who, message) {
        // Html encode display name and message.
        var encodedName = $('<div />').text(who).html();
        var encodedMsg = $('<div />').text(message).html();
        // Add the message to the page.
        $('#chat').append('<li><strong>' + encodedName
            + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
    };

    // Start the connection.
    $.connection.hub.start().done(function () {
        $('#sendmessage').click(function () {
            // Call the Send method on the hub.
            chat.server.sendChatMessage($('#displayname').val(), $('#message').val());
            // Clear text box and reset focus for next comment.
            $('#message').val('').focus();
        });
    });
});

테스팅 여기에 이미지 설명 입력


안녕하세요 친구, 늦은 피드백에 대해 죄송합니다! 그러나 CONNECTIONID의 손실을 어떻게 방지 할 수 있습니까? 감사합니다.
이고르

5
@lgao 모르겠어요.
The Muffin Man

이 줄이 필요한 이유 --- Clients.Group ( "2@2.com"). addChatMessage (name, message); ??
Thomas

@Thomas 아마도 데모를 위해 포함했을 것입니다. 이것은 하드 코딩 되었기 때문에 특정 그룹에 방송하는 또 다른 방법이 있어야합니다.
The Muffin Man

이 간단한 솔루션은 특정 로그인 사용자에게 메시지를 보내는 문제를 해결했습니다. 간단하고 빠르고 이해하기 쉽습니다. 가능하다면이 답변을 여러 번 찬성 할 것입니다.
Rafael AMS

5

다음은 공급자를 사용하지 않고 특정 사용자를 대상으로 지정하기 위해 SignarR을 사용하는 방법입니다.

 private static ConcurrentDictionary<string, string> clients = new ConcurrentDictionary<string, string>();

 public string Login(string username)
 {
     clients.TryAdd(Context.ConnectionId, username);            
     return username;
 }

// The variable 'contextIdClient' is equal to Context.ConnectionId of the user, 
// once logged in. You have to store that 'id' inside a dictionaty for example.  
Clients.Client(contextIdClient).send("Hello!");

2
당신이 사용하는 방법 contextIdClient을 didnt를 :( 그것을 얻을
네오

2

기능 은 SignalR 테스트 를 참조하십시오.

테스트 "SendToUser"는 일반 owin 인증 라이브러리를 사용하여 전달 된 사용자 ID를 자동으로 가져옵니다.

시나리오는 여러 장치 / 브라우저에서 연결 한 사용자가 있으며 모든 활성 연결에 메시지를 푸시하려는 것입니다.


감사합니다! 그러나 프로젝트 버전 2.0은 여기서 SignalR을 컴파일하지 않습니다. . (불행하게도 나는 그것을 액세스 할 수 없습니다.
이고르

0

오래된 스레드이지만 샘플에서 이것을 발견했습니다.

services.AddSignalR()
            .AddAzureSignalR(options =>
        {
            options.ClaimsProvider = context => new[]
            {
                new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
            };
        });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.