是否可以使用HttpModule对SignalR进行身份验证

时间:2017-05-31 22:05:35

标签: asp.net authentication signalr owin httpmodule

我正在开发一个使用HttpModule执行自定义身份验证和授权的应用程序。我的问题是在SignalR上下文对象中无法访问HttpModule中设置的用户标识。

我在自定义身份验证逻辑之后在我的HttpModule BeginRequest处理程序中执行以下操作:

var userClaims = new List<Claim>();
userClaims.Add(new Claim(ClaimTypes.NameIdentifier, <some id>));
userClaims.Add(new Claim(ClaimTypes.Name, <some name>));
userClaims.Add(new Claim(ClaimTypes.Email, <da email>));
userClaims.Add(new Claim(ClaimTypes.Authentication, "true"));

var id = new ClaimsIdentity(userClaims);
var principal = new ClaimsPrincipal(new[] { id });
Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal;

我认为这绝对会使以后的所有内容都像请求被验证一样,但事实并非如此。

我创建了一个SignalR AuthorizeAttribute类来处理如下所示的身份验证:

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthAttribute : AuthorizeAttribute
{
    public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
    {
        if (HttpContext.Current.Request.Path.StartsWith("/signalr/connect"))
        {
            var test = (ClaimsPrincipal)HttpContext.Current.User;
            var test2 = (ClaimsPrincipal)Thread.Current.Principal;
        }

        return true;
    }

    public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubContext, bool appliesToMethod)
    {
        var test = (ClaimsPrincipal)hubContext.Hub.Context.User;
        return true;
    }
}

所以我的计划是从AuthorizeHubMethodInvocation方法中访问hubContext.Hub.Context.User var来执行我需要的任何自定义授权。但是,这只包含默认的WindowsPrincipal。

如果我查看AuthorizeHubConnection调用(实际上是一个常规的HTTP请求而不是一个websocket调用),我看到HttpContext.Current对象也没有按照它应该设置User。

我确实看到我可以访问HttpContext.Current.Items集合。我认为我可以使用它将Principal从模块抛到SignalR上下文,但我不确定这是我应该做的。

最好是简单地将HttpModule重写为OWIN中间件吗?看起来,如果我们更新到ASP.NET 5,我将不得不改变一些东西;没有什么比MS产品更能为您提供工作保障。

1 个答案:

答案 0 :(得分:2)

我忘了我刚才发布这个问题了。我最后在MS文章Authentication and Authorization for SignalR Hubs的评论中解释了我的解决方案。在尝试为auth实现OWIN中间件之后,我发现我必须做一些愚蠢的配置来为所有请求运行所有模块,这是低效的。我无法弄清楚如何为所有请求运行Auth OWIN中间件组件,所以我放弃了这种方法并坚持使用我的HttpModule。以下是我在上面链接的页面上发布的SignalR auth解决方案的摘要:

1)创建一个AuthorizeAttribute类,如文章中所示:

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthAttribute : AuthorizeAttribute

2)使用您创建的auth类装饰您的Hub类。命名约定似乎是auth类本身的(SomeName)属性和集线器装饰的(SomeName)。

[CustomAuth]
public class ServerWebSocket : Hub

3)不要覆盖文档中显示的“UserAuthorized”方法,而是覆盖以下方法(我从其他SO帖子中得到了这个,但我现在找不到它):

public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubContext, bool appliesToMethod)

为了实际授权用户,我在HttpModule中捕获了SignalR连接请求,并在HttpContext Items集合中设置了一个项目,如下所示:

if (req.Path.StartsWith("/signalr/connect") || req.Path.StartsWith("/signalr/reconnect"))
{
    var user_info = doFullAuth(<some token>);
    HttpContext.Current.Items.Add("userDat", user_info);
}

这实际上是设置的,这样如果用户没有权限,连接请求将在HttpModule中被完全拒绝。所以我实际上根本没有实现SignalR auth方法“AuthorizeHubConnection”。但是在“AuthorizeHubMethodInvocation”方法中,我通过调用在原始连接请求上设置的HttpContext.Current.Items来访问用户数据,并执行自定义逻辑以确定用户是否可以访问方法。

如果您想要验证每个保护静态文件的请求等,这是我能想到的最佳方法。