在 .NET 8 中使用自定义令牌身份验证掌握 SignalR Hub 安全性

最近在练习做一个 Web 开发项目,需要使用 WebSockets 传输数据,实现实时通信。这是一个 React.js 项目,后端是 .NET。

虽然 MSDN 提供了出色的顶级文档,但它通常缺少高级用例所需的低级细节。

一种这样的场景是使用自定义令牌对 SignalR Hub 进行身份验证。是的,自定义令牌,而不是 JWT 或默认 Bearer 令牌。本文探讨如何实现这一点。最后,您将拥有一个需要身份验证并使用自定义令牌的 SignalR Hub。

自定义Token

我们将使用的自定义令牌是 Base64 编码的用户信息分隔字符串,格式如下:

userId:userName

从这个标记中,我们将提取userId并userName创建声明。

项目设置

以下是设置项目的基本步骤:

创建一个.NET项目:

dotnet new webapi

添加 SignalR 服务:

在Program.cs文件中,构建应用程序时注册 SignalR 服务:

builder.Services.AddSignalR();

创建 Hub :

创建一个名为 的目录hubs,并添加一个名为 的文件GameHub.cs。执行以下操作:

public class GameHub : Hub

{

public override Task OnConnectedAsync()

{

return base.OnConnectedAsync();

}

public override Task OnDisconnectedAsync(Exception? exception)

{

return base.OnDisconnectedAsync(exception);

}

}

映射中心:

将其GameHub作为端点公开Program.cs:

app.MapHub<GameHub>("/hubs/game");

实现自定义令牌认证

要使用自定义令牌并从中提取用户信息,我们需要一个自定义身份验证方案。在 .NET 中,身份验证方案是一个命名标识符,它指定用于对用户进行身份验证的方法或协议,例如 Cookie、JWT 持有者令牌或 Windows 身份验证。对于此场景,我们将创建一个名为的方案CustomToken。

自定义身份验证方案实现

定义自定义令牌方案选项:

public class CustomTokenSchemeOptions : AuthenticationSchemeOptions

{

public CustomTokenSchemeOptions()

{

Events = new CustomTokenEvents();

}

public new CustomTokenEvents Events

{

get => (CustomTokenEvents)base.Events!;

set => base.Events = value;

}

}

定义方案处理程序: 包含验证令牌和提取用户声明的逻辑

:CustomTokenSchemeHandler

public class CustomTokenSchemeHandler : AuthenticationHandler<CustomTokenSchemeOptions>

{

private new CustomTokenEvents Events => (CustomTokenEvents)base.Events!;

public CustomTokenSchemeHandler(

IOptionsMonitor<CustomTokenSchemeOptions> options,

ILoggerFactory logger,

UrlEncoder encoder) : base(options, logger, encoder) {}

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()

{

var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options);

await Events.MessageReceivedAsync(messageReceivedContext);

var token = messageReceivedContext.Token ?? GetTokenFromQuery();

if (token is null)

{

return AuthenticateResult.NoResult();

}

byte[] data = Convert.FromBase64String(token);

string decodedString = Encoding.UTF8.GetString(data);

string[] userInfoArray = decodedString.Split(":");

var claims = new[]

{

new Claim(ClaimTypes.Name, userInfoArray[1]),

new Claim(ClaimTypes.Sid, userInfoArray[0])

};

var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));

var ticket = new AuthenticationTicket(principal, Scheme.Name);

return AuthenticateResult.Success(ticket);

}

private string? GetTokenFromQuery()

{

var accessToken = Context.Request.Query["access_token"].ToString();

return string.IsNullOrEmpty(accessToken) ? null : accessToken;

}

}

配置身份验证方案:

在以下位置注册自定义身份验证方案Program.cs:

builder.Services.AddAuthentication("CustomToken")

.AddScheme<CustomTokenSchemeOptions, CustomTokenSchemeHandler>("CustomToken", opts =>

{

opts.Events = new CustomTokenEvents

{

OnMessageReceived = context =>

{

var accessToken = context.Request.Query["access_token"];

var path = context.HttpContext.Request.Path;

if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs/game"))

{

context.Token = accessToken;

}

return Task.CompletedTask;

};

};

});

免责声明

本文介绍的实现灵感来自 .NET 官方存储库中的 BearerTokenScheme 源代码。我们对其进行了调整以适应此场景的自定义令牌要求。

总结

通过实施此自定义令牌身份验证方案,您可以保护 SignalR 中心并根据应用程序的独特要求定制身份验证过程。此方法允许对令牌验证和声明提取进行细粒度控制,从而确保安全可靠的实时通信系统。

欢迎随意扩展此实现,添加额外的验证、日志记录或与外部身份提供商的集成,以获得更全面的解决方案。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
Broadm12 天前
C# - 获取枚举描述 - 使用增量源生成器
.net8·源代码生成·source generator·增量源生成器
lixww.cn2 个月前
ASP.NET Core SignalR向部分客户端发消息
javascript·websocket·vue·asp.net core·signalr
lixww.cn2 个月前
ASP.NET Core SignalR的协议协商
asp.net core·signalr
lixww.cn2 个月前
ASP.NET Core SignalR的分布式部署
redis·消息队列·asp.net core·signalr
鱼是一只鱼啊2 个月前
.netframeworke4.6.2升级.net8问题处理
开发语言·.net·.net8
三天不学习4 个月前
ASP.NET Core SignalR 双工通信
后端·asp.net·signalr·websockets·双工通信
敲厉害的燕宝7 个月前
SignalR——聊天室实践
前端·javascript·html·signalr
lee5767 个月前
.net 8.0 下 Blazor 通过 SignalR 与 Winform 交互
blazor·signalr
武穆逸仙10 个月前
如何在.NET中集成SignalR
.net·signalr