SignalR JWT声称IUserIdProvider中缺少。 JWT承载OnMessageReceived无法触发

时间:2019-04-30 10:11:11

标签: c# asp.net-core jwt signalr

我正在尝试使用.NET客户端和服务器设置SignalR。

我只需要一种自定义方式来提供已连接客户端的ID,看来唯一的方法就是在实现IUserIdProvider接口时填充属于HubConnectionContext参数的声明。

在我的客户上,我正在构建一个按预期工作的JWT(验证它是否正确构建)。

在我的服务器上,我已按照here

提供的确切说明进行操作

但是,不会触发OnMessageReceived回调,因此令牌将被忽略,随后IUserIdProvider中的Claims数组为空。

值得注意的是,客户端连接时仍会调用IUserIdProvider。

这是我的客户端JWT生成代码:

        _hubConnection = new HubConnectionBuilder()
            .WithUrl($"{_hubUrl}", options => options.AccessTokenProvider = () =>
            {
                var jwtHandler = new JwtSecurityTokenHandler();
                var credentials = new SigningCredentials(_securityKey, SecurityAlgorithms.HmacSha256);
                var jwt = new JwtSecurityToken(claims: new[] { new Claim("Id", _id) }, signingCredentials: credentials);
                var tokenString = jwtHandler.WriteToken(jwt);
                return Task.FromResult(tokenString);
            })
            .Build();

这是我的Startup ConfigureServices函数:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IUserIdProvider, MyIdProvider>();

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                LifetimeValidator = (before, expires, token, param) =>
                {
                    return true;
                },
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateActor = false,
                ValidateLifetime = true,
                IssuerSigningKey = SecurityKey
            };
            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    // breakpoints never hit...
                    var accessToken = context.Request.Query["access_token"];
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrWhiteSpace(accessToken) &&
                        path.StartsWithSegments("myHub"))
                    {
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                }
            };
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddSignalR();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc(Version, new OpenApiInfo
            {
                Version = Version,
                Title = Name
            });
        });            
    }

,最后是我的IUserIdProvider实现:

    public class MyIdProvider : IUserIdProvider
{
    public string GetUserId(HubConnectionContext connection)
    {
        var id = connection.User.Claims.First(x => x.Type == "Id").Value;
        return id;
    }
}

谢谢。

1 个答案:

答案 0 :(得分:0)

要使其正常工作,我必须解决几个问题。

首先,集线器需要[Authorize]属性,否则将永远不会调用OnMessageReceived。

第二,我丢失了app.UseAuthentication(),它也是管道正常运行所必需的。

进行了这些更改之后,我的主张正确了。