Skip to content

How does a client tell the server what group it wants to be in or what user it is? #7255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
grahambunce opened this issue Jun 22, 2018 — with docs.microsoft.com · 9 comments
Assignees
Labels
Source - Docs.ms Docs Customer feedback via GitHub Issue
Milestone

Comments

Copy link

grahambunce commented Jun 22, 2018

Scenario: Multiple listeners deployed worldwide, each listener belongs to a group. When a message is published it belongs to every listener in the group (or if you want to design it as such, to that user which has multiple listeners attached). How does the listener, using the .NET client, tell the hub what group it's in (or what user it is)?

From what I can gather (this article doesn't make it clear), I can pass context on the client query string and then access this HTTP context in the OnConnected event of the Hub.

I worked this out by trial and error..... I'm sorry, but a number of these examples are just too simple and leave many questions unanswered as a tutorial.


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

@Rick-Anderson
Copy link
Contributor

@anurse please comment.

@Rick-Anderson Rick-Anderson added this to the Backlog milestone Jun 22, 2018
@Rick-Anderson Rick-Anderson added the Source - Docs.ms Docs Customer feedback via GitHub Issue label Jun 22, 2018
@analogrelay
Copy link
Contributor

The client does not have control over what groups it is in. The server is the only thing that can assign groups (this is partially a security measure). For a client to join a group, it needs to call a Server hub method that will add it to the group.

@analogrelay
Copy link
Contributor

Alternatively you can use users, in which case it depends on how you have configured ASP.NET Core Authentication.

@grahambunce
Copy link
Author

@anurse Maybe this is a fundamental misunderstanding then. I have thousands of physical IoT devices worldwide, allocated to different customers. When I want to send content to those those devices, I only want to send to those devices for a single customer. Groups therefore seems the approach I should use.

When the IoT device connects to the Hub it knows what customer its for, so it tells the hub this - the only way I can work out how to do this is via the URL used during the HubConnectionBuilder process. The hub picks this up during it's OnConnecting event and then, based on the customer in the Url it's inspected from the incoming request, assigns the ConnectionId to an appropriate hub group for that customer.

I'm guessing this is not the recommended way to pass context from a client to the Hub.

So what is the recommended way, and can we have an example please?

@analogrelay
Copy link
Contributor

There are two primitives that can work for you here in SignalR: Groups and Users.

Groups are 100% controlled by the server. But of course, since the client can invoke methods on the server, you can have a server hub method that adds a client to a group. For example:

public class DeviceHub: Hub
{
    public async Task Initialize(string customerId)
    {
        await Groups.AddAsync(Context.ConnectionId, $"Customer:{customerId}");
    }
}

Then on the client:

await connection.StartAsync();
await connection.InvokeAsync("Initialize", customerId);

The risk here is that you are trusting the client to provide the right customer ID. Nothing would stop a malicious user from simply specifying a random customer ID and becoming part of the group.

The other option is Users. The "User ID" for a connection is assigned as part of authenticating the connection, and then it basically just serves as an "automatic" group. I do think that's a better approach for your scenario. That all depends on how you are authenticating users though. What kind of security/authentication are you using for clients? Do you have a security token (such as a JWT token) that you use to identify the customer?

@grahambunce
Copy link
Author

@anurse Ok... the invokeAsync from the client can work and yes, we are using JWT tokens too.. (not sure how to enable that yet, but I'll work on it). My scenario was simplified though - we have customer level security tokens but they have multiple locations too. We really only want to send to a specific customer-location not to all customers, so JWT may not be enough on its own.

How does either scenario handle reconnects though? Reading through some of the previous issues, the .NET client now handles reconnects automatically. What isn't clear from the Docs (or I can't find it) is how it does it and how does the client know there has been an issue.

For example, a server restart will clear down the connections and the groups they are in - I don't really want a persistent store server-side as this can get stale, so the client needs to know the connection has been dropped and then when it reconnects automatically it can get itself added back into the appropriate group.

There is the Closed event on HubConnection class to help with this, but I can't see a reconnected event (or something similar such as an exposed ConnectionState) to know when it's ok to invoke the Initialize method on the hub again.

(this comes back to my original concern, which is these tutorial docs leave out a lot of functionality that is necessary for a robust system we'd consider putting into production)

@analogrelay
Copy link
Contributor

We really only want to send to a specific customer-location not to all customers, so JWT may not be enough on its own.

This is definitely a case where groups are good. Once you've "authenticated" that the connection is from the right user the client can call a method on the server to assign itself to the group

How does either scenario handle reconnects though? Reading through some of the previous issues, the .NET client now handles reconnects automatically.

Where did you get that impression? ASP.NET Core SignalR does not automatically reconnect, that was intentionally removed, so I'd like to figure out what content you're reading that's telling you otherwise so we can clear it up.

There is the Closed event on HubConnection class to help with this, but I can't see a reconnected event (or something similar such as an exposed ConnectionState) to know when it's ok to invoke the Initialize method on the hub again.

In ASP.NET Core SignalR, once a connection is closed, it's gone. However, the HubConnection object can be reused to start a new connection. If you call StartAsync in the Closed event handler, a new connection will be started, with all the same configuration options (including JWT tokens) and you can safely call your Initialize method again because this is a brand new connection.

this comes back to my original concern, which is these tutorial docs leave out a lot of functionality that is necessary for a robust system we'd consider putting into production

It's early days and tutorials often cover just the basics, we're getting the docs moving, and questions like this are exactly how we figure out what information people need. So thanks for the input!

@grahambunce
Copy link
Author

@anurse

I'd like to figure out what content you're reading that's telling you otherwise so we can clear it up

I found it here https://github.com/aspnet/SignalR/issues/1057 and this PR aspnet/SignalR#1147

Reading it again, I notice your comment that auto-reconnect will be later - I think I got confused with the PR and the issue.

Thanks for the info so far, it really is helping to fill in the blanks.

@analogrelay
Copy link
Contributor

Ok, good, I'm glad that our docs aren't making the wrong impression here. Sometimes the issues are a little bit unclear, because they're primarily just for planning our own work and reporting problems/feature requests 😉 .

Are there some specific modifications to the docs that would help clear this up? Writing full tutorials is a lot of work, but explanatory docs are a lot easier to write/update. We've got #6757 filed to talk about reconnect scenarios, so feel free to comment there if there's anything you think we could add.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Source - Docs.ms Docs Customer feedback via GitHub Issue
Projects
None yet
Development

No branches or pull requests

4 participants