Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server to Server authentication for client - Single threaded

I am creating a login-server for my client to server application.

Basically there are 5 servers, and all of these servers are connected to one login-server.

The client can connect to any of these 5 servers, but it needs to authenticate with username and a password. Authentication should be done in the login server, and the login server should return an answer to the actual server that should return the answer to the client.

So its like that:

Client -> Server -> Login-server -> Server -> Client (response code)

Now, I am using Netty and it's NIO, it's not thread-per-client. Now, to authenticate with NIO, we must wait for a response to arrive from the login-server, and that can take a while and delay other clients that want to login, actually you can't just wait for an answer with NIO like that. So I thought of an idea on how can I make it work. My idea was run the request on a different thread and have an event with onResponse(String key, int responseCode) method and then put the client's channel in a map with a generated key, so that way we can know who the response belongs to. So when we authenticate, we send the key, and user's data.

But I feel that this is a bad way and there is a more efficient method to do this. Any ideas?

like image 596
Mitch Avatar asked Sep 25 '22 14:09

Mitch


2 Answers

Assuming that you have full control of all system:

Assign an ID for each client connection in the server. Then when you need to authenticate the user, include this connection ID in the request from the server to the login server and return without waiting for the reply from the login server.

Some time in the future your server will receive login response from the login server. If the login response contains the client connection ID - use that ID to find a connection from a server to a client and relay that reply back to the client.

like image 73
jpou Avatar answered Sep 28 '22 05:09

jpou


Here is how I did it.

Setup

Create a Channel wrapper class, so that you can identify which channel belongs to which client.

public class CustomChannel implements Channel {

    private final Channel channel;
    private final String clientId;

    ...
}

Create a custom ChannelMatcher for matching client's channel:

public class CustomChannelMatcher implements ChannelMatcher {
    private final String clientId;

    public CustomChannelMatcher(String clientId) {
        this.clientId = clientId;
    }

    @Override
    public boolean matches(Channel channel) {
        if (channel instanceof CustomChannel) {
            return clientId.equals(((CustomChannel) channel).getClientId());
        }
        return false;
    }

    ...
}

Handling Request

In your client handler, use ChannelGroup to keep track of your clients' channels.

ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

...

channelGroup.add(new CustomChannel(ctx.channel(), clientId));

// send request to another server without blocking

Handling Response

In your server handler, use your CustomChannelMatcher to match the client's channel.

// when the server responds sometimes later

channelGroup.writeAndFlush(responseMessage, 
    new CustomChannelMatcher(clientId));

The code above will find a matching client's channel and write the message to it.

like image 29
paulboony Avatar answered Sep 28 '22 06:09

paulboony