SignalR - 使用访问令牌进行身份验证
Posted
技术标签:
【中文标题】SignalR - 使用访问令牌进行身份验证【英文标题】:SignalR - authenticating with access token 【发布时间】:2014-02-11 04:19:26 【问题描述】:我一直在构建一个 Web 服务,到目前为止,它完全由 ASP.NET Web API 调用组成。我现在需要将 SignalR 添加到组合中,但我想知道如何保持安全方面的一致性。
我目前正在使用 OAuth 持有者令牌(使用 OWIN 身份验证),因此我的客户端基本上会有一个 access_token,我通常只需将其添加到任何 Web API 调用的标头中。但是,我如何对 SignalR 执行相同(或类似)操作?我会在创建连接时或每次通话时进行身份验证吗?而且,最重要的是,我如何首先指定访问令牌?
谢谢。
【问题讨论】:
javascript WebSocket API 不允许设置请求标头。您最好的选择是在请求 url 查询字符串上设置 access_token。 谢谢。我可以这样做,但是如何配置服务器端以读取查询字符串并确定和设置集线器的身份? @Barguast 您可以创建一个 HubPipelineModule 来设置有效令牌的用户身份或拒绝无效令牌的访问。您需要重写以使其工作的两种方法是OnBeforeConnect
和OnBeforeIncoming
。 msdn.microsoft.com/en-us/library/…
谢谢。希望在某处有更多关于此的内容?我可以看到模块如何拦截请求,以及可能如何解密令牌(虽然它会很混乱),但我看不到如何在上下文中看到 User 属性。我曾假设我必须做的工作是配置 OWIN 而不是 SignalR。
我想我已经取得了一些进展。我已经按照这个问题的答案:***.com/questions/20585872/…,现在能够在查询字符串中提供访问令牌并在服务器上从中获取身份。我的 WebAPI 控制器现在都从 Authorization 标头或查询字符串获取主体。但是,SignalR 中的 User 属性仍然是默认的“未验证”值!如何在 OWIN 配置中设置该属性的值?
【参考方案1】:
我编写了一个示例,已经帮助一些人使用 SignalR 身份验证。 希望对你也有帮助。
https://github.com/louislewis2/AngularJSAuthentication
Barguast,很抱歉我的回答过于简短。通过链接,您可能会了解到有太多活动部分,我无法准确地解释您也应该注意的最重要部分。示例代码包含三个项目,您将只关注 .Api 和 .Web 项目。
如果您有任何需要进一步澄清或指导的部分,请告诉我,我很乐意帮助您,就像所有其他遇到需要相同示例的人一样,这就是我被要求构建的原因首先给出的例子。
【讨论】:
我认为评论(由 LowQualityPosts-Review-Queue 自动生成)已经足够了,但请阅读 SO 的指南 谢谢。看起来您以与我相同的方式绕过它 - 将访问令牌添加到查询字符串,并修改服务以在此处查找令牌。它对我来说效果很好,我还没有看到任何其他方法。 很高兴听到你说对了。还有另一种方法,您可以将令牌放在标头中,但是该路线存在一个大问题。如您所知,signalr 支持 websocket,对我来说这很重要。 websockets 不支持添加自定义标头,因此走这条路,您将不得不忘记使用 websockets 作为传输。除此之外,我没有找到其他方法。【参考方案2】:(这太晚了:D但可能对某人有用) 您可以在客户端将 accessTokenFactory 添加到 hubConnection,然后在您的后端(asp.net core 3.1)中检查它。
您必须从后端覆盖 JwtBearerEvents 并检查 OnMessageReceived 中的 access_token,以及您的集线器端点路径
services.AddAuthentication(options =>
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(options =>
// other options here ... //
options.Events = new JwtBearerEvents
OnMessageReceived = context =>
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/ConnectionHub"))) // for me my hub endpoint is ConnectionHub
context.Token = accessToken;
return Task.CompletedTask;
;
);
从客户端,添加您的 accessToken 选项(TypeScript):
public async startConnection(): Promise<void>
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl('https://localhost:5001/ConnectionHub', // ConnectionHub is hub endpoint
accessTokenFactory: () => this.getAccessToken(),
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
).build();
await this.hubConnection.start();
// ....
getAccessToken(): string
return 'your token' ;
微软说: 单独的 hub 方法也可以应用 [Authorize] 属性
[Authorize]
public class ChatHub : Hub
public async Task Send(string message)
// ... send a message to all users ...
[Authorize("Administrators")]
public void BanUser(string userName)
// ... ban a user from the chat room (something only Administrators can do) ...
最后,您可以在任何 hub 的方法中读取和检查声明或身份属性:
public override async Task OnConnectedAsync()
// Get UserID. Assumed the user is logged before connecting to chat and userid is saved in session.
string userID = Context.User.Identity.Name;
// Get ChatHistory and call the client function. See below
await GetHistoryAsync(userID);
await base.OnConnectedAsync();
【讨论】:
我已经按照您所写的方式设置了后端 StartUp.cs,但是我不清楚如何在getAccessToken()
方法中访问令牌,特别是 UserData
?
UserData 是我自己的类变量。您可以从您之前存储它的位置发送您的 jwt。对于测试,请尝试直接返回您的 jwt。以上是关于SignalR - 使用访问令牌进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用参考令牌的 ASPNETCore SignalR 身份验证
带有 JWT 身份验证的 SignalR Core Android 客户端返回 NULL