如何基于HTTP头创建自定义身份validation机制?
我将旧版本的问题留在底部。
我想为SignalR客户端实现自定义身份validation。 在我的例子中,这是Java客户端(Android)。 不是网络浏览器。 没有表单身份validation,没有Windows身份validation。 这些是使用java库的普通vanilla客户端。
所以,假设连接到HUB的客户端传递自定义标头。 我需要以某种方式根据此标头validation用户。 这里的文档提到它是可能的,但没有提供有关如何实现它的任何细节。
这是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 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); }
PS下面的原始问题是我“简化”问题的愿望。 因为我可以访问OnConnected
回调中的标头。 我认为有简单的方法可以放下连接…
使用Signal R和自定义身份validation机制。 我只是检查连接客户端是否有连接请求传入的某些标头。
问题是 – 如何拒绝或不连接未通过支票的用户? 这里的文档并没有真正解释这种情况。 提到使用证书/标题 – 但没有关于如何在服务器上处理它的示例。 我不使用Forms或Windows身份validation。 我的用户 – 安卓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(); }
所以我刚刚创建了一个自定义授权属性并覆盖了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)]
:
事实上,接受的答案是错误的。 令人惊讶的是,授权属性应该用于授权(也就是说,您应该使用它来检查请求经过身份validation的用户是否有权执行所需的操作)。
此外,由于您使用了错误的机制,因此您没有设置HttpContext.Current.User.Identity
。 因此,您没有明确的方法将用户信息传递给您的业务/授权逻辑。
第三,这样做你将无法使用Clients.User()
方法向特定用户发送消息,因为SignalR将无法在用户和连接之间进行映射。
正确的方法是插入OWIN身份validation管道。 这是一篇很好的文章 ,详细解释和演示如何实现在OWIN中使用的自定义身份validation。
我不打算在此复制粘贴,只需按照它并确保您实现所有必需的部分:
- 选项
- 处理器
- 中间件
有了这些之后,将它们注册到OWIN中:
app.Map("/signalr", map => { map.UseYourCustomAuthentication(); var hubConfiguration = new HubConfiguration { Resolver = GlobalHost.DependencyResolver, }; map.RunSignalR(hubConfiguration); });