Hi,
I am using ABP 3.6.2. Could you please advise me (or provide me link), how can I implement authentication? Please be aware, in my case the client here would be a third party application.
One way, in my mind is, let client call the Authenticate API of my application which will return him a token and then let the client connect to our signalr hub by passing that token. But I don't know how should I validate that token in my signalr Hub onConnected event?
Please help....
Regards, Mahendra
9 Answer(s)
-
0
You can check <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero-core/blob/master/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Host/Startup/AuthConfigurer.cs#L64">https://github.com/aspnetzero/aspnet-ze ... rer.cs#L64</a>.
In this case, user retrieves a encrypted token and when user sends it via query string, it is resolved here.
-
0
Hi,
The link you shared is not opening and throwing 404 error.
-
0
You need to login with your GitHub account to access the private repo. You can invite yourself here: <a class="postlink" href="https://aspnetzero.com/LicenseManagement">https://aspnetzero.com/LicenseManagement</a>
-
0
Here is my complete code of SignalR. The question is when JavaScript client runs, it does not hit the breakpoint at QueryStringTokenResolver function of AuthConfigurer class.
I am sure, I must be missing something. Please advise....
----------------------------Application Service iVend365ApplicationModule.cs---------------------------- [DependsOn( typeof(iVend365CoreModule), typeof(AbpAspNetCoreSignalRModule) )] public class iVend365ApplicationModule : AbpModule { …… …... } ----------------------------Application Service iVend365Hub.cs---------------------------- public override Task OnConnectedAsync() { return base.OnConnectedAsync(); }
public override Task OnDisconnectedAsync(Exception exception) { ConnectedClient DisConnectedClient = AppStatic.ConnectedClients.Where(p => p.ConnectionId == Context.ConnectionId).SingleOrDefault(); AppStatic.ConnectedClients.Remove(DisConnectedClient); Clients.All.SendAsync("PrintConnectedPOS", "POS - " + DisConnectedClient.POSKey + " DisConnected"); return base.OnDisconnectedAsync(exception); } public void RegisterPOS(Int32 TenantId, string POSKey) { ConnectedClient connectedClient = new ConnectedClient() { TenantId = TenantId, POSKey = POSKey, ConnectionId = Context.ConnectionId }; AppStatic.ConnectedClients.Add(connectedClient); Clients.All.SendAsync("PrintConnectedPOS", "POS - " + POSKey + " Connected"); }
----------------------------MVC Web Startup.cs---------------------------- public IServiceProvider ConfigureServices(IServiceCollection services) { ……. services.AddCors(options => options.AddPolicy("CorsPolicy", builder => { builder .AllowAnyHeader() .AllowAnyMethod() .AllowAnyOrigin() .AllowCredentials(); }));
services.AddSignalR(options => { options.KeepAliveInterval = TimeSpan.FromSeconds(15); }); ……………. ……………. }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ………… app.UseCors("CorsPolicy");
app.UseSignalR(routes => { routes.MapHub<iVend365Hub>("/signalr"); }); ……………… ………….. }
-----------------MVC Web AuthConfigurer.cs---------------------------- private static Task QueryStringTokenResolver(MessageReceivedContext context) { if (!context.HttpContext.Request.Path.HasValue || !context.HttpContext.Request.Path.Value.StartsWith("/signalr")) { //We are just looking for signalr clients return Task.CompletedTask; }
var qsAuthToken = context.HttpContext.Request.Query["enc_auth_token"].FirstOrDefault(); if (qsAuthToken == null) { //Cookie value does not matches to querystring value return Task.CompletedTask; } //Set auth token from cookie context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase); return Task.CompletedTask; }
----------------------JavaScript Client (Another Project)-------------------- <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <script src="Scripts/signalr.js"></script> <script> const connection = new signalR.HubConnectionBuilder() //.withUrl("http://ivend365retail-signalrtest.azurewebsites.net/signalr?enc_auth_token=ABCD") .withUrl("http://localhost:62114/signalr") .configureLogging(signalR.LogLevel.Information) .build();
connection.start().then(function () { connection.send("RegisterPOS", 1018, "418307399342882834"); //connection.send("RegisterPOS", 972, "441464738128330770"); }); connection.on("GetDeltaQueue", function (message) { console.log(message); }); connection.on("PrintConnectedPOS", function (message) { console.log(message); }); </script>
</body> </html>
-
0
The question is when JavaScript client runs, it does not hit the breakpoint at QueryStringTokenResolver function of AuthConfigurer class.
Show a screenshot of where your breakpoint is.
Tip: Wrap your code in the following for formatting and readability:
[code]
[/code:2x0u0yv0] A shortcut is to highlight your code and click on the </> button in the formatting toolbar.
You can wrap the contents of each file in a separate code block.
-
0
Hi,
Let me try to explain you once again. My JavaScript client was successfully able to connect to My SignalR Hub and the data exchange between client and server was happening successfully till the time there is no authentication implemented.
Now to implement client authentication, I did the following:
In the CitiXsys.iVend365.Web.Mvc Project's AuthConfigurer.cs class, I add the following:
public static void Configure(IServiceCollection services, IConfiguration configuration) { ..... if (bool.Parse(configuration["Authentication:JwtBearer:IsEnabled"])) { ....... options.Events = new JwtBearerEvents { OnMessageReceived = QueryStringTokenResolver }; } } /* This method is needed to authorize SignalR javascript client. * SignalR can not send authorization header. So, we are getting it from query string as an encrypted text. */ private static Task QueryStringTokenResolver(MessageReceivedContext context) { if (!context.HttpContext.Request.Path.HasValue || !context.HttpContext.Request.Path.Value.StartsWith("/signalr")) { //We are just looking for signalr clients return Task.CompletedTask; } var qsAuthToken = context.HttpContext.Request.Query["enc_auth_token"].FirstOrDefault(); if (qsAuthToken == null) { //Cookie value does not matches to querystring value return Task.CompletedTask; } //Set auth token from cookie try { context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase); } catch (Exception ex) { } return Task.CompletedTask; }
Also In My Hub Class, I added the attribute AbpAuthorize.
[AbpAuthorize] public class iVend365Hub : AbpCommonHub { public iVend365Hub(IOnlineClientManager onlineClientManager, IClientInfoProvider clientInfoProvider) : base(onlineClientManager, clientInfoProvider) { } public override Task OnConnectedAsync() { return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { ConnectedClient DisConnectedClient = AppStatic.ConnectedClients.Where(p => p.ConnectionId == Context.ConnectionId).SingleOrDefault(); AppStatic.ConnectedClients.Remove(DisConnectedClient); Clients.All.SendAsync("PrintConnectedPOS", "POS - " + DisConnectedClient.POSKey + " DisConnected"); return base.OnDisconnectedAsync(exception); } public void RegisterPOS(Int32 TenantId, string POSKey) { ConnectedClient connectedClient = new ConnectedClient() { TenantId = TenantId, POSKey = POSKey, ConnectionId = Context.ConnectionId }; AppStatic.ConnectedClients.Add(connectedClient); Clients.All.SendAsync("PrintConnectedPOS", "POS - " + POSKey + " Connected"); } }
Now From Postman, I called the API <a class="postlink" href="http://localhost:62114//api/TokenAuth/Authenticate">http://localhost:62114//api/TokenAuth/Authenticate</a> and get the accesstoken and encryptedAccessToken.
Now from my client I am trying the connect to SignalR Hub by passing encryptedAccessToken as query string as below:
const connection = new signalR.HubConnectionBuilder() .withUrl("http://localhost:62114/signalr?enc_auth_token=wNYmO41/48SHNstaLVXxHCCre29BZQl1NhC6NM3R3rzpXtPQxVzH6jEzA/QhXFN5tu6Fk7pO53uppm1mVXMZgxbyRVz26dnepi/FyB6axBY+6gq1GL+uRQgoiFUCjRN2p8w6LevViwKlHyWZZJZO1DGVSjAi1m2U+og9pkHw9/QZzDt3yiLMoYW1WDdaXPnlFLgt0N06nDVJ/TNUnhw0BCL43otzv+OMKuLeY+h0rGYDeO90t9A/K6VhhzUXsg1AnxPiqcPpiycwoLyZAZ53/kzTppy8m3SYqaKUsjOESlkAY8kF2r7y154j9qEUcLk9utfC3PSRp0oSuNrm4VSVguDREewfyWbN2sKRaHtlXs5UxIgBWyA348/T9keWz4iRdlPaw7R66Toe+whj4AhIwXhBIQMqxokrK1Sq2LBTHHwJPAUsTkzsTwP1v0/VcSC9oGwxy27ovrSXKN9G5/i43T5nZW5vR+X2Q4SVFS4wi03ifhySoobT6PgEUGaET9Xp62cBKgzEM589+abpKPMhAs4533XlfdfWRr6UxNUUF0LMuya3RB2NCE1h6ccRo0vujM9DMiKxU04lQ5ezjQV6k1lqFx0CjsCZEscMH91ICvjAuAnUXkHpCeNyfJl5Om+Xen1Ef57GeI0WV/5Rj6h6FJt+z8xDXCZJ8ikvpQe+tjjvX+vAfQdyR5nFgHC/vCNiab0x/qnWgJyoQOcXxMUZ43HXsRIruWCre/gpHvfEysGKsk7V3PLpdgESTQVNniZPHs7EypH8r8+T9VRiR1X964QUmqnaBMn3pNkrMBm1gEqyB1sP7HNlz3dLvjRRUX3JcD2/Pe5elhZBjnYRLu8Ay7pJaEzXgEeJ3cRGkq8DbxXZEg5O+f3+VjYssQDjesGGg8ZDwaBDriBSWjOtvnw7OFqvD7qk4xzXqFZpIRnqkJ/70mLCFfTGTxpjMWnFMTu9xh8Snm2/uPex48biHG30f4BXw0xmW2xZ521GIRdgFIE=") .configureLogging(signalR.LogLevel.Information) .build(); connection.start().catch(err => console.error(err.toString()));
But it throws the error in the following code:
context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase);
The error returned is: Invalid length for a Base-64 char array or string.
Please help...
-
0
What's the value of qsAuthToken?
-
0
Hi,
I think, I have resolved it by using encodeURIComponent in the javascript client to encode the encrypted access token...
Anyway...thanks for your support....
-
0
That's great :)