首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SignalR AccessTokenProvider可与TypeScript客户端配合使用,但不能与.NET客户端配合使用

SignalR AccessTokenProvider可与TypeScript客户端配合使用,但不能与.NET客户端配合使用
EN

Stack Overflow用户
提问于 2019-12-13 05:38:26
回答 1查看 2K关注 0票数 2

我正在尝试通过C# .NET客户端中的HubConnection传递access_token。然而,结果与我通过TypeScript客户端看到的结果并不一致。这种不一致会导致C# .NET客户端中的授权失败,但会导致TypeScript客户端中的授权成功。

相关代码如下:

TypeScript

代码语言:javascript
运行
复制
var builder = new signalr.HubConnectionBuilder();
builder.withUrl(hubUrl, {accessTokenFactory: () => token});

C#

代码语言:javascript
运行
复制
var builder = new HubConnectionBuilder();
builder.WithUrl(url, o => {
  o.AccessTokenProvider = () => Task.FromResult(_token);
  //I've tried the following as well
  //o.Headers.Add("Authorization", "Bearer " + _token);
});

TypeScript代码生成一个HTTP请求,如下所示:

代码语言:javascript
运行
复制
POST http://localhost:5000/machine/negotiate?negotiateVersion=1 HTTP/1.1
Host: localhost:5000
Connection: keep-alive
Content-Length: 0
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGVzdCIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluaXN0cmF0b3IiLCJleHAiOjE1NzYxODYwMTYsImlzcyI6Im5TY3J5cHQsIEluYy4iLCJhdWQiOiJuU3R1ZGlvIFVzZXIifQ.qxAzu-NgzlnfCqyysiML4Z0_s6UBTeRb7wcuGno9rk4
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) nstudio-pro/1.0.0 Chrome/78.0.3905.1 Electron/7.0.0 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Referer: http://localhost:3000/main_window
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US
Cookie: .AspNetCore.Identity.Application=CfDJ8Dp0ZrsdLf1KpYnUb_iitp4gyw5TR5uJhBjiI8pFnzSSEM9ALjY6XbRVrMURJ_NrkK9IAD0Xlqy3l6HEQNJkfGG7vwCRfj5x4NjEW4Msm5GoQMuhG6epa3Q3r8QDhdC4z3tJSS0bRZ_EXvmnnnVWYvw4lILddLABWnf3leeMXrKUmq6AUAJPy1SVgj4fJQ8BGOo5HLPZDLZxN-m3ZV0jUaDkOf_mosTAz7JTjI53bAlxD0hi78YYzkVfpa8dEs8gXOTD85f96_m5DGGoMMCnvsjMP6ST1Q87rWHCCsxUPPLaH_A2xc6JpUqvzV-Pur6KtE8oFmcen4jq7h0kL2akXWUvTApZIxY7lFvFx7x4-8andT1DP7T3tRNdWnoRNRotSoQCp4HtS3Cz0GRwcyaKyhuFBjdUFMj1H0FKDYOEJEiarVMX0bElqgTjGGr7ZiOPyTJq1yHmCOraqdbP7YMycTWfC4F1tPXS0v4KxxNo8F2o31MYlhCx_sTIgEjJUHjdh9iugr401GYzazV3reL4M64YAliZ3fynzXf7ZNVqwUg-OvDzXd0nba4E3BVd_hQDwlssaWYq0DAZvrwO56iUwv1y9e-wehaH6OzocmvujVLX_HYG20BsXN6YdLiPPfhqNdkay50AaTuvXF2kq-exJTEnYBuc9U6eTWn9--mEFXKe4VQlTnn97AGvLfnOt_QrhUK4Pc88Z9q3hHNu7MNhfnE

而C#代码创建:

代码语言:javascript
运行
复制
POST http://localhost:5000/machine/negotiate?negotiateVersion=1 HTTP/1.1
Host: localhost:5000
User-Agent: Microsoft.AspNetCore.Http.Connections.Client/3.1.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGVzdCIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluaXN0cmF0b3IiLCJleHAiOjE1NzYxODYxOTIsImlzcyI6Im5TY3J5cHQsIEluYy4iLCJhdWQiOiJuU3R1ZGlvIFVzZXIifQ.i_m-hnyZfPmFoUSX9VHPjSk-LP7UtpJlFafEuJBR66Q
X-Requested-With: XMLHttpRequest
Content-Length: 0

然后,下一个请求如下:

TypeScript

代码语言:javascript
运行
复制
GET http://localhost:5000/machine?id=n2xReT4vy3KPuakBsaSBuA&access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGVzdCIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluaXN0cmF0b3IiLCJleHAiOjE1NzYxODYwMTYsImlzcyI6Im5TY3J5cHQsIEluYy4iLCJhdWQiOiJuU3R1ZGlvIFVzZXIifQ.qxAzu-NgzlnfCqyysiML4Z0_s6UBTeRb7wcuGno9rk4 HTTP/1.1
Host: localhost:5000
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) nstudio-pro/1.0.0 Chrome/78.0.3905.1 Electron/7.0.0 Safari/537.36
Upgrade: websocket
Origin: http://localhost:3000
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US
Cookie: .AspNetCore.Identity.Application=CfDJ8Dp0ZrsdLf1KpYnUb_iitp4gyw5TR5uJhBjiI8pFnzSSEM9ALjY6XbRVrMURJ_NrkK9IAD0Xlqy3l6HEQNJkfGG7vwCRfj5x4NjEW4Msm5GoQMuhG6epa3Q3r8QDhdC4z3tJSS0bRZ_EXvmnnnVWYvw4lILddLABWnf3leeMXrKUmq6AUAJPy1SVgj4fJQ8BGOo5HLPZDLZxN-m3ZV0jUaDkOf_mosTAz7JTjI53bAlxD0hi78YYzkVfpa8dEs8gXOTD85f96_m5DGGoMMCnvsjMP6ST1Q87rWHCCsxUPPLaH_A2xc6JpUqvzV-Pur6KtE8oFmcen4jq7h0kL2akXWUvTApZIxY7lFvFx7x4-8andT1DP7T3tRNdWnoRNRotSoQCp4HtS3Cz0GRwcyaKyhuFBjdUFMj1H0FKDYOEJEiarVMX0bElqgTjGGr7ZiOPyTJq1yHmCOraqdbP7YMycTWfC4F1tPXS0v4KxxNo8F2o31MYlhCx_sTIgEjJUHjdh9iugr401GYzazV3reL4M64YAliZ3fynzXf7ZNVqwUg-OvDzXd0nba4E3BVd_hQDwlssaWYq0DAZvrwO56iUwv1y9e-wehaH6OzocmvujVLX_HYG20BsXN6YdLiPPfhqNdkay50AaTuvXF2kq-exJTEnYBuc9U6eTWn9--mEFXKe4VQlTnn97AGvLfnOt_QrhUK4Pc88Z9q3hHNu7MNhfnE
Sec-WebSocket-Key: 7XIeUeqljhqwC4AencqJxg==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

C#

代码语言:javascript
运行
复制
GET http://localhost:5000/machine?id=ZB_6NJvMFDpt0cRhoqiWkw HTTP/1.1
Host: localhost:5000
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGVzdCIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluaXN0cmF0b3IiLCJleHAiOjE1NzYxODYxOTIsImlzcyI6Im5TY3J5cHQsIEluYy4iLCJhdWQiOiJuU3R1ZGlvIFVzZXIifQ.i_m-hnyZfPmFoUSX9VHPjSk-LP7UtpJlFafEuJBR66Q
X-Requested-With: XMLHttpRequest
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: yUAfoo7mcEy8e/j4irLl5w==

我在服务器上的Startup.cs如下所示:

代码语言:javascript
运行
复制
services.AddAuthentication(jwtAuthScheme)
                .AddJwtBearer(jwtAuthScheme, options =>
                {
                    options.Events = new JwtBearerEvents
                    {
                        OnMessageReceived = context =>
                        {
                            if (context.Request.Query.ContainsKey("access_token"))
                            {
                                context.Token = context.Request.Query["access_token"];
                            }
                            else if (context.Request.Headers.TryGetValue("Authorization", out var value) && value.Count > 0)
                            {
                                context.Token = value[0].Substring("Bearer ".Length);
                            }
                            return Task.CompletedTask;
                        }
                    };
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        LifetimeValidator = (before, expires, token, param) =>
                        {
                            return expires > DateTime.UtcNow;
                        },
                        ValidateAudience = true,
                        ValidAudience = jwtHandler.TokenAudience,
                        ValidateIssuer = true,
                        ValidIssuer = jwtHandler.TokenIssuer,
                        ValidateActor = false,
                        ValidateLifetime = true,
                        IssuerSigningKey = jwtKey,
                        SaveSigninToken = true
                    };
                    options.SaveToken = true;
                    options.Audience = jwtHandler.TokenAudience;
                });
            services.AddAuthorization();

我有什么地方做错了吗?为什么服务器无法从标头中获取令牌,为什么C# .NET客户端不将令牌放在查询字符串中?

EN

回答 1

Stack Overflow用户

发布于 2019-12-17 18:14:11

我也有同样的问题(与您的情况唯一不同的是,我没有使用JwtBearer,令牌是在集线器端自己处理的)。C#客户端无法在SignalR集线器(Asp.Net Core3.1,Linux x64)上进行身份验证,而Javascript客户端很容易做到这一点。

C#客户端:

代码语言:javascript
运行
复制
connection = new HubConnectionBuilder()
    .WithUrl("https://xxx/signalr", options =>
    { 
         options.AccessTokenProvider = () => Task.FromResult("abcdefgh");
    })
    .WithAutomaticReconnect()
    .Build();
 connection.StartAsync();

Javascript客户端:

代码语言:javascript
运行
复制
 var connection = new signalR.HubConnectionBuilder()
       .withUrl('https://xxx/signalr', { accessTokenFactory: () => 'abcdefgh' })
       .withAutomaticReconnect()
       .build();
 connection.start().then(function () {...

我发现在第一种情况下,集线器一侧的request.query如下所示:wss://xxx/signalr?id=XVJmpqCyqtV76jLp1M9ew (没有传递access_token参数)。

在第二种情况下,它看起来正常(存在access_token参数):wss://xxx/signalr?id=XVJmpqCyqtV76jLp1M9ew&access_token=abcdefgh

更新

好吧,现在我很清楚了。对于非基于web的客户端(如C#客户端),令牌始终通过授权承载标头发送;对于基于web的客户端(javascript),令牌通过查询字符串发送。

里奇,在你的例子中,我认为,你不需要从授权头中提取令牌并手动将其分配给context.Token -它是自动完成的。因此,您的OnMessageReceived C#处理程序可能如下所示:

代码语言:javascript
运行
复制
options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
         if (context.Request.Query.ContainsKey("access_token"))
         {
              context.Token = context.Request.Query["access_token"];
         }
         return Task.CompletedTask;
    }
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59313098

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档