Пользователь + socket.io, как подключить этого же пользователя в разных вкладках браузера?
Socket.io действительно генерирует каждому подключению свой уникальный handshake и это правильно и в порядке вещей.
Если интересует вывод пользователей онлайн в списке на сайте, например, то решить проблему можно при помощи callback() функции.
Мы будем передавать на сигналер-сервер user_id, например через PHP и затем проверять, есть ли этот user_id в массиве подключенных пользователей.
Пример server.js:userlist = {}; // Массив юзеров
io.sockets.on('connection', function(socket) {
	socket.on('connect', function(data, callback) {
		socket.user_id = data.user_id; // в user_id передаём идентификатор пользователя
		if(socket.user_id in userlist) {
		    callback(false); // Ага, этот юзер уже открыл вкладку, значит ничего не делаем
		} else {
		    callback(true); // А вот тут он новенький
		    userlist[socket.user_id] = data; // Фигачим его в массив
		    UpdateUserList(); // Обновляем список онлайн юзеров
		} 
	});
        // При дисконнекте
        socket.on('disconnect', function() {
             delete userlist[socket.user_id];
             // Тут немного магии, чтобы юзеры в списке онлайн на клиенте не моргали, когда например они ходят по ссылкам сайта
             setTimeout(function () {
                 UpdateUserList();
             }, 1000);
        });
    
        function UpdateUserList() {
		io.sockets.emit('updateusers', userlist);
	}
});
Но, получается, что одному пользователю соответствует несколько socket.id или это нормально?
Это нормально. socket.io в любом случае надо каждое подключение назвать уникально, чтобы можно было с ним работать отдельно не зависимо от того, есть ли такой логин в Вашем массиве или нет.