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

Is it possible to use HttpModule to authenticate for SignalR

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

我在自定义身份验证逻辑后在我的 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 class 来处理如下所示的身份验证:

[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 对象也没有按应有的方式设置用户。

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

是否最好将 HttpModule 简单地重写为 OWIN 中间件?看来无论如何我都得改变东西 when/if 我们更新到 ASP.NET 5;没有什么比 MS 产品更能为您提供工作保障了。

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

1) 创建 AuthorizeAttribute class,如文章中所述:

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

2) 使用您创建的身份验证 class 装饰您的集线器 class。命名约定似乎是 auth class 本身的 (SomeName)Attribute 和集线器装饰的 (SomeName)。

[CustomAuth]
public class ServerWebSocket : Hub

3) 不是覆盖文档中显示的 "UserAuthorized" 方法,而是覆盖以下方法(我从其他一些 SO post 那里得到它,但我现在找不到它):

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 来访问用户数据,并执行自定义逻辑以确定用户是否可以访问某个方法。

如果您想对每个请求进行身份验证以保护静态文件等,这是我能想到的最好的方法。