如何基于HTTP头创建自定义认证机制?

13

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

我想为SignalR客户端实现自定义身份验证。在我的情况下,这是Java客户端(Android)。不是Web浏览器。没有表单身份验证,也没有Windows身份验证。这些都是使用Java库的纯香草HTTP客户端。

因此,假设客户端连接到HUB时传递了自定义标头。我需要根据此标头对用户进行身份验证。文档这里提到这是可能的,但没有给出任何有关如何实现的详细信息。

这是我从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);
        }

附言:以下原始问题是我希望“简化”事情的愿望。因为我可以在OnConnected回调中访问标头。我认为有一种简单的方法可以在那里立即断开连接。


使用自定义身份验证机制的Signal R。我只需检查连接请求中是否传递了某些标头,以确定连接客户端。

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

这是我想要拒绝连接的Hub中的代码..

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

那么,答案就是“不可能”吗? - katit
在客户端,您可以访问一个端点,尝试验证用户是否应该能够连接,并根据该逻辑运行您的中心连接代码。这听起来对您可行吗? - Mark C.
1
我不确定为什么应该考虑_client_。我想确保如果我告诉SignalR不要填充内部连接,它就不会这样做。客户端可以是任何东西,也许是具有适当请求结构的DOS攻击。从我所看到的 - 在我的代码中没有办法告诉它只是在头文件中看不到我需要看到的内容时放弃连接?通过Hub代码告诉客户端断开连接是不合逻辑的,因为客户端甚至可能不支持这一点。 - katit
我想寻找一种方法,根据头部内容使用我的自定义代码对用户进行身份验证。 - katit
不,我想拒绝客户端的连接。我不想调用客户端代码,因为它们可能甚至不支持它(例如自动机器人)。如果有一种基于标头检查用户的方法,那么OnConnected就不会执行,这对我来说是可以接受的。 - katit
显示剩余8条评论
2个回答

8

所以,我刚刚创建了一个自定义的授权属性,并重写了AuthorizeHubConnection方法以获取请求访问并实现你试图通过头部进行的逻辑,看起来它正在工作。

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)]):

在此输入图片描述


你能否更新你的问题并展示一下你是如何将头部放置到请求中的? - Mark C.
完成。我还尝试添加标准的“Authorization”头,但这里没有。它在“OnConnected”方法中。 - katit
这是长轮询,不是websocket。 - katit
我现在明白了。这个链接有帮助吗? - Mark C.
没问题。我的回答有用吗?如果没有,我会删除它。 - Mark C.
显示剩余13条评论

6
事实上,被接受的答案是错误的。授权属性应该用于授权(也就是说,您应该使用它来检查请求的已认证用户是否有权执行所需的操作)。
另外,由于您使用了不正确的机制,因此没有设置HttpContext.Current.User.Identity。因此,您没有明确的方法将用户信息传递给业务/授权逻辑。
第三,这样做将无法使用Clients.User()方法向特定用户发送消息,因为SignalR将无法在用户和连接之间进行映射。
正确的方法是插入到OWIN身份验证管道中。这是一篇优秀的文章详细说明和演示如何实现用于OWIN的自定义身份验证。
我不会在这里复制粘贴它,只需按照它并确保实现所有必需的部分:
  • 选项
  • 处理程序
  • 中间件
在拥有这些内容之后,将它们注册到OWIN即可。
app.Map("/signalr", map =>
{
   map.UseYourCustomAuthentication();

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

   map.RunSignalR(hubConfiguration);
});

本文的关键部分在于 https://dotnetcodr.com/2015/11/26/wiring-up-a-custom-authentication-method-with-owin-in-web-api-part-4-putting-the-components-to-work/。 - CRice
是的,将身份验证与授权分开是更好的选择 - 这是一个很好的答案。 - CRice

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