与SignalR服务器断开客户端连接

15

我正在使用SignalR 1和MVC4 C# Web应用程序,采用表单身份验证。我的布局页面中有JavaScript代码:

$(documnet).ready(function(){
       connect to hub code ...
})

我想从服务器端的帐户控制器和方法中断开用户与中心的连接,并在其进行登录并验证通过后重新开始连接。

public ActionResult LogOn(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (System.Web.Security.Membership.ValidateUser(model.UserName, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName, false);
            ....here , disconnect from hub
            ....to make the user reconnect     
}

我想这样做的原因是因为如果用户在登录后更改为已验证状态而连接仍然存在,SignalR会抛出错误。这个错误是:

连接ID格式不正确。

7个回答

29

您无法在服务器上停止和启动SignalR连接。您需要调用

$.connection.hub.stop(); //on the client before the user attempts to log on and then call 
$.connection.hub.start(); //after the log on attempt has completed.

在每个文档准备就绪状态下,我都会调用 "$.connection.hub.start();"。在这之前调用 "$.connection.hub.stop();" 是否可行? - Haddar Macdasi
当用户连接到中心时,您需要从客户端获取它,并存储以便与任何新连接进行比较,这也将防止冒充攻击。 - Kelso Sharp
3
如果一名员工刚被解雇,他们需要撤销他们的访问权限,那会发生什么?我需要能够断开任何打开的SignalR会话。必须有一种方法。 - Brain2000

12

你想实现的一种方法是在客户端编写一个SignalR断开事件,服务器可以通过该事件调用。也许可以像这样:

myHub.client.serverOrderedDisconnect = function (value) {
    $.connection.hub.stop();
};

然后,在服务器上,类似于这样:

Clients.Client(Context.ConnectionId).serverOrderedDisconnect();

但是我如何在“LogOn”操作内的服务器端代码中获取Context.ConnectionId? - Haddar Macdasi
1
是的,但客户端上的那段代码可以被移除。我有点困惑,为什么这样的功能不仅仅通过服务器端支持呢? - kewur

6
如果有人仍在寻找解决方案(SignalR版本2.4.1):
GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>().GetConnections().First(c => c.ConnectionId == "YourId").Disconnect();

2
你如何在aspnetcore中实现它? - bboyle1234
抱歉,但我只使用ASP.NET。 - Лопатка Подзаборная

4
尝试使用JavaScript控制所有内容。以下是一个注销示例,登录也类似。
来自http://www.asp.net/signalr/overview/security/introduction-to-security
如果用户身份验证状态在存在活动连接的情况下更改,则用户将收到一个错误,指出“不能在活动SignalR连接期间更改用户身份验证状态”。在这种情况下,您的应用程序应重新连接到服务器,以确保协调连接 ID 和用户名。例如,如果您的应用程序允许用户在存在活动连接的情况下注销,则连接的用户名将不再与传递给下一个请求的名称匹配。您需要在用户注销之前停止连接,然后重新启动连接。 然而,重要的是要注意,大多数应用程序不需要手动停止和启动连接。如果您的应用程序在注销后将用户重定向到另一个页面,例如Web Forms应用程序或MVC应用程序中的默认行为,或在注销后刷新当前页面,则活动连接将自动断开,并且不需要任何其他操作。 以下示例显示了在用户状态更改时如何停止和启动连接。
<script type="text/javascript">
$(function () {
    var chat = $.connection.sampleHub;
    $.connection.hub.start().done(function () {
        $('#logoutbutton').click(function () {
            chat.connection.stop();
            $.ajax({
                url: "Services/SampleWebService.svc/LogOut",
                type: "POST"
            }).done(function () {
                chat.connection.start();
            });
        });
    });
});


2

1

试试这个:

public ActionResult LogOn(LoginModel model, string returnUrl) {
    if (ModelState.IsValid) {
        if (System.Web.Security.Membership.ValidateUser(model.UserName, model.Password)) {
            FormsAuthentication.SetAuthCookie(model.UserName, false);
            connection.Stop();
        }
}

假设你的连接句柄是connection。挑战在于在你的Action方法中访问到connection对象的句柄。

但是我如何在“LogOn”操作中的服务器端代码中获取“connection”对象? - Haddar Macdasi
1
好问题。没有好好考虑这个问题。除非将其添加到会话中,否则可能不会很容易地获得它,但这似乎是错误的... - Dave Alperovich

-7

将以下函数复制并粘贴到您的 Hub 中

Use HttpContext.Current.Response.End();

强制客户端在您的中心断开连接

2
除了语法和排版问题之外,这个解决方案是否存在任何技术问题会导致负投票? - Synesthetic Symphony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接