+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 this to implement signalR hubs authorization and authentication by passing the bearer token through a connection string, but seems like either the bearer token is not going, or something else is wrong somewhere, which is why am here seeking HELP...these are my codes... QueryStringBearerAuthorizeAttribute: this is the class in charge of verification
using ImpAuth.Entities; using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.Owin.Security; using Microsoft.Owin.Security.OAuth; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; namespace ImpAuth.Providers { using System.Security.Claims; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; using Microsoft.AspNet.SignalR.Owin; public class QueryStringBearerAuthorizeAttribute : AuthorizeAttribute { public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) { var token = request.QueryString.Get("Bearer"); var authenticationTicket = Startup.AuthServerOptions.AccessTokenFormat.Unprotect(token); if (authenticationTicket == null || authenticationTicket.Identity == null || !authenticationTicket.Identity.IsAuthenticated) { return false; } request.Environment["server.User"] = new ClaimsPrincipal(authenticationTicket.Identity); request.Environment["server.Username"] = authenticationTicket.Identity.Name; request.GetHttpContext().User = new ClaimsPrincipal(authenticationTicket.Identity); return true; } public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod) { var connectionId = hubIncomingInvokerContext.Hub.Context.ConnectionId; // check the authenticated user principal from environment var environment = hubIncomingInvokerContext.Hub.Context.Request.Environment; var principal = environment["server.User"] as ClaimsPrincipal; if (principal != null && principal.Identity != null && principal.Identity.IsAuthenticated) { // create a new HubCallerContext instance with the principal generated from token // and replace the current context so that in hubs we can retrieve current user identity hubIncomingInvokerContext.Hub.Context = new HubCallerContext(new ServerRequest(environment), connectionId); return true; } return false; } } }
and this is my start up class....
using ImpAuth.Providers; using Microsoft.AspNet.SignalR; using Microsoft.Owin; using Microsoft.Owin.Cors; using Microsoft.Owin.Security.Facebook; using Microsoft.Owin.Security.Google; //using Microsoft.Owin.Security.Facebook; //using Microsoft.Owin.Security.Google; using Microsoft.Owin.Security.OAuth; using Owin; using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Web; using System.Web.Http; [assembly: OwinStartup(typeof(ImpAuth.Startup))] namespace ImpAuth { public class Startup { public static OAuthAuthorizationServerOptions AuthServerOptions; static Startup() { AuthServerOptions = new OAuthAuthorizationServerOptions { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), Provider = new SimpleAuthorizationServerProvider() // RefreshTokenProvider = new SimpleRefreshTokenProvider() }; } public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; } public static GoogleOAuth2AuthenticationOptions googleAuthOptions { get; private set; } public static FacebookAuthenticationOptions facebookAuthOptions { get; private set; } public void Configuration(IAppBuilder app) { //app.MapSignalR(); ConfigureOAuth(app); app.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain //EnableJSONP = true EnableDetailedErrors = true }; // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); }); HttpConfiguration config = new HttpConfiguration(); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); WebApiConfig.Register(config); app.UseWebApi(config); } public void ConfigureOAuth(IAppBuilder app) { //use a cookie to temporarily store information about a user logging in with a third party login provider app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie); OAuthBearerOptions = new OAuthBearerAuthenticationOptions(); OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new SimpleAuthorizationServerProvider() }; // Token Generation app.UseOAuthAuthorizationServer(OAuthServerOptions); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); //Configure Google External Login googleAuthOptions = new GoogleOAuth2AuthenticationOptions() { ClientId = "1062903283154-94kdm6orqj8epcq3ilp4ep2liv96c5mn.apps.googleusercontent.com", ClientSecret = "rv5mJUz0epWXmvWUAQJSpP85", Provider = new GoogleAuthProvider() }; app.UseGoogleAuthentication(googleAuthOptions); //Configure Facebook External Login facebookAuthOptions = new FacebookAuthenticationOptions() { AppId = "CHARLIE", AppSecret = "xxxxxx", Provider = new FacebookAuthProvider() }; app.UseFacebookAuthentication(facebookAuthOptions); } } }
and this is the knockout plus jquery code on the client....
function chat(name, message) { self.Name = ko.observable(name); self.Message = ko.observable(message); } function viewModel() { var self = this; self.chatMessages = ko.observableArray(); self.sendMessage = function () { if (!$('#message').val() == '' && !$('#name').val() == '') { $.connection.hub.qs = { Bearer: "yyCH391w-CkSVMv7ieH2quEihDUOpWymxI12Vh7gtnZJpWRRkajQGZhrU5DnEVkOy-hpLJ4MyhZnrB_EMhM0FjrLx5bjmikhl6EeyjpMlwkRDM2lfgKMF4e82UaUg1ZFc7JFAt4dFvHRshX9ay0ziCnuwGLvvYhiriew2v-F7d0bC18q5oqwZCmSogg2Osr63gAAX1oo9zOjx5pe2ClFHTlr7GlceM6CTR0jz2mYjSI" }; $.connection.hub.start().done(function () { $.connection.hub.qs = { Bearer: "yyCH391w-CkSVMv7ieH2quEihDUOpWymxI12Vh7gtnZJpWRRkajQGZhrU5DnEVkOy-hpLJ4MyhZnrB_EMhM0FjrLx5bjmikhl6EeyjpMlwkRDM2lfgKMF4e82UaUg1ZFc7JFAt4dFvHRshX9ay0ziCnuwGLvvYhiriew2v-F7d0bC18q5oqwZCmSogg2Osr63gAAX1oo9zOjx5pe2ClFHTlr7GlceM6CTR0jz2mYjSI" }; $.connection.impAuthHub.server.sendMessage($('#name').val(), $('#message').val()) .done(function () { $('#message').val(''); $('#name').val(''); }) .fail(function (e) { alert(e) }); }); } } $.connection.impAuthHub.client.newMessage = function (NAME, MESSAGE) { //alert(ko.toJSON(NAME, MESSAGE)); var chat1 = new chat(NAME, MESSAGE); self.chatMessages.push(chat1); } } ko.applyBindings(new viewModel());
and here is my hub class...
using ImpAuth.Providers; using Microsoft.AspNet.SignalR; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace ImpAuth { public class impAuthHub : Hub { [QueryStringBearerAuthorize] public void SendMessage(string name, string message) { Clients.All.newMessage(name, message); } } }
...now the problem comes when i try to invoke an authenticated hub class and i get this error
caller is not authenticated to invove method sendMessage in impAuthHub
but then i change this method in QueryStringBearerAuthorizeAttribute class to alway return true like this
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod) { var connectionId = hubIncomingInvokerContext.Hub.Context.ConnectionId; // check the authenticated user principal from environment var environment = hubIncomingInvokerContext.Hub.Context.Request.Environment; var principal = environment["server.User"] as ClaimsPrincipal; if (principal != null && principal.Identity != null && principal.Identity.IsAuthenticated) { // create a new HubCallerContext instance with the principal generated from token // and replace the current context so that in hubs we can retrieve current user identity hubIncomingInvokerContext.Hub.Context = new HubCallerContext(new ServerRequest(environment), connectionId); return true; } return true; }
...it works....WHAT IS THE PROBLEM WITH MY CODE OR IMPLEMENTATION?