如何创建基于 HTTP header 的自定义身份验证机制?

How to create custom authentication mechanism based on HTTP header?

我将旧版本的问题放在底部。

我想为 SignalR 客户端实现自定义身份验证。在我的例子中,这是 java 个客户 (Android)。不是网络浏览器。没有 Forms 身份验证,没有 Windows 身份验证。这些是使用 java 库的普通 http 客户端。

所以,假设客户端连接到 HUB 时通过自定义 header。我需要以某种方式基于此 header 对用户进行身份验证。文档 here 提到这是可能的,但没有提供有关如何实施它的任何细节。

这是我在 Android 方面的代码:

hubConnection = new HubConnection("http://192.168.1.116/dbg", "", true, new NullLogger());
        hubConnection.getHeaders().put("SRUserId", userId);
        hubConnection.getHeaders().put("Authorization", userId);

        final HubProxy hubProxy = hubConnection.createHubProxy("SignalRHub");
        hubProxy.subscribe(this);


        // Work with long polling connections only. Don't deal with server sockets and we
        // don't have WebSockets installed
        SignalRFuture<Void> awaitConnection = hubConnection.start(new LongPollingTransport(new NullLogger()));
        try
        {
            awaitConnection.get();

            Log.d(LOG_TAG, "------ CONNECTED to SignalR -- " + hubConnection.getConnectionId());
        }
        catch (Exception e)
        {
            LogData.e(LOG_TAG, e, LogData.Priority.High);
        }

P.S。下面的原始问题是我对 "simplify" 的渴望。因为我可以在 OnConnected 回调中访问 headers。我认为有一种简单的方法可以在那里断开连接..


将 Signal R 与自定义身份验证机制结合使用。我只是检查连接客户端是否已通过连接请求传入某些 header。

问题是 - 如何拒绝或不连接未通过检查的用户?文档 here 并没有真正解释这种情况。提到使用 certificates/headers - 但没有关于如何在服务器上处理它的示例。我不使用表单或 windows 身份验证。我的用户 - android java 台设备。

这是我的集线器中我想拒绝连接的代码。

public class SignalRHub : Hub
{
    private const string UserIdHeader = "SRUserId";

    private readonly static SignalRInMemoryUserMapping Connections = new SignalRInMemoryUserMapping();

    public override Task OnConnected()
    {
        if (string.IsNullOrEmpty(Context.Headers[UserIdHeader]))
        {
            // TODO: Somehow make sure SignalR DOES NOT connect this user!
            return Task.FromResult(0);
        }

        Connections.Add(Context.Headers[UserIdHeader], Context.ConnectionId);
        Debug.WriteLine("Client {0}-{1} - {2}", Context.Headers[UserIdHeader], Context.ConnectionId, "CONNECTED");

        return base.OnConnected();
    }

所以我刚刚创建了一个自定义授权属性并覆盖了 AuthorizeHubConnection 方法以访问请求并实现了您尝试使用 Header 执行的逻辑,它似乎是正在工作。

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace SignalR.Web.Authorization
{
    public class HeadersAuthAttribute : AuthorizeAttribute
    {
        private const string UserIdHeader = "SRUserId";

        public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
        {
            if (string.IsNullOrEmpty(request.Headers[UserIdHeader]))
            {
                return false;
            }

            return true;
        }
    }
}

枢纽

 [HeadersAuth]
    [HubName("messagingHub")]
    public class MessagingHub : Hub
    {

    }

在控制台中产生这个(如果图片没有显示,它是 [Failed to load resource: the server responded with a status of 401 (Unauthorized)]):

事实上,接受的答案是错误的。令人惊讶的是,Authorization 属性应用于授权(也就是说,您应该使用它来检查请求 authenticated 用户是否被授权执行所需的操作)。

此外,由于您使用了不正确的机制,因此您没有设置 HttpContext.Current.User.Identity。因此,您没有明确的方法将用户信息传递给您的业务/授权逻辑。

第三,这样做你将无法使用 Clients.User() 方法向特定用户发送消息,因为 SignalR 将无法在用户和连接之间进行映射。

正确的方法是插入 OWIN 身份验证管道。 Here is an excellent article 详细解释和演示如何实现要在 OWIN 中使用的自定义身份验证。

我不会在此处复制粘贴它,只需按照它执行并确保您实现了所有必需的部分:

  • 选项
  • 处理程序
  • 中间件

获得这些后,将它们注册到 OWIN 中:

app.Map("/signalr", map =>
{
   map.UseYourCustomAuthentication();

   var hubConfiguration = new HubConfiguration
   {
       Resolver = GlobalHost.DependencyResolver,
   };

   map.RunSignalR(hubConfiguration);
});