+i used this solution to implement Token Based Authentication using ASP.NET Web API 2, Owin, and Identity...which worked out excellently well. i used this other solution and thi
Can't comment so adding my answer after the comments on Peter's excellent answer.
Did a bit more digging and the user id that I had set in my custom owin authorization provider was hiding here (complete hub method shown).
[Authorize]
public async Task<int> Test()
{
var claims = (Context.User.Identity as System.Security.Claims.ClaimsIdentity).Claims.FirstOrDefault();
if (claims != null)
{
var userId = claims.Value;
//security party!
return 1;
}
return 0;
}
More added for texas697:
Startup.Auth.cs add this to ConfigureAuth() if not already there:
app.Map("/signalr", map =>
{
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider() //important bit!
});
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
Resolver = GlobalHost.DependencyResolver,
};
map.RunSignalR(hubConfiguration);
});
The custom auth provider looks like this:
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var value = context.Request.Query.Get("access_token");
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
return Task.FromResult<object>(null);
}
}
I followed this:
first Add the JWT to the query string:'
this.connection = $['hubConnection']();
this.connection.qs = { 'access_token': token}
then in thestartup.cs
,before JwtBearerAuthentication, add the token to the header:
app.Use(async (context, next) =>
{
if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"]) && context.Request.QueryString.HasValue)
{
var token = context.Request.QueryString.Value.Split('&').SingleOrDefault(x => x.Contains("access_token"))?.Split('=')[1];
if (!string.IsNullOrWhiteSpace(token))
{
context.Request.Headers.Add("Authorization", new[] { $"Bearer {token}" });
}
}
await next.Invoke();
});
var keyResolver = new JwtSigningKeyResolver(new AuthenticationKeyContainer());
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = ConfigurationUtil.ocdpAuthAudience,
ValidIssuer = ConfigurationUtil.ocdpAuthZero,
IssuerSigningKeyResolver = (token, securityToken, kid, validationParameters) => keyResolver.GetSigningKey(kid)
}
});
ValidateSignalRConnectionData(app);
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true
};
app.MapSignalR(hubConfiguration);
You need to configure your signalr like this;
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
var hubConfiguration = new HubConfiguration
{
Resolver = GlobalHost.DependencyResolver,
};
map.RunSignalR(hubConfiguration);
});
Then you need to write a basic custom OAuthBearerAuthenticationProvider for signalR which accepts access_token as query string.
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var value = context.Request.Query.Get("access_token");
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
return Task.FromResult<object>(null);
}
}
After this all you need is to send access_token with signalr connection as querystring.
$.connection.hub.qs = { 'access_token': token };
And for your hub just ordinary [Authorize] attribute
public class impAuthHub : Hub
{
[Authorize]
public void SendMessage(string name, string message)
{
Clients.All.newMessage(name, message);
}
}
Hope this helps. YD.