2016-07-28 2 views
1

Я использую токены JWT через пакет nJWT для аутентификации моих пользователей на свой Socket.io с использованием пакета socket.io-jwt.Использование жетонов JWT. Есть ли лучший подход?

Более или менее код выглядит следующим образом. Пользователь отправляет запросы POST для воспроизведения/входа через HTML-форму для создания токена JWT. Затем клиент socket.io инициализирует этот токен.

/** 
* Create Express server. 
*/ 
const app = express(); 
const http = require('http').Server(app); 
const io = require('socket.io')(http); 
const socketioJwt = require('socketio-jwt'); 

app.set('jwt.secret', secureRandom(256, { 
    type: 'Buffer' 
})); 

app.post('/play/login', (req, res) => { 
    // validate user's req.body.email and req.body.password 

    const claims = { 
     iss: "http://app.dev", // The URL of your service 
     sub: "user-1", // The UID of the user in your system 
     scope: "game" 
    }; 

    const jwt = nJwt.create(claims, app.get("jwt.secret")); 
    const token = jwt.compact(); 

    new Cookies(req,res).set('access_token', token, { 
     httpOnly: true, 
     secure: process.env.ENVIRONMENT === "production" 
    }); 

    tokenUserRelations[token] = req.body.email; 

    res.json({ 
     code: 200, 
     token: token 
    }); 
}); 

/** 
* Add Socket IO auth middleware 
*/ 
io.set('authorization', socketioJwt.authorize({ 
    secret: app.get("jwt.secret"), 
    handshake: true 
})); 

io.sockets.on('connection', function (socket) { 

    socket.on('chat message', function (req) { 
     io.emit("chat message emit", { 
      email: tokenUserRelations[socket.handshake.query.token], 
      msg: req.msg 
     }); 
    }); 

    socket.on('debug', function (req) { 
     io.emit("debug emit", { 
      playersOnline: Object.keys(tokenUserRelations).length 
     }); 
    }); 

    socket.on('disconnect', function (req) { 
     delete tokenUserRelations[socket.handshake.query.token]; 
    }); 
}); 
io.listen(app.get('socket.port'),() => { 
    console.log('Started! Socket server listening on port %d in %s mode', app.get('socket.port'), app.get('env')); 
}); 

Прямо сейчас, он работает правильно, но для того, чтобы отслеживать электронные письма от лексем, я должен был сделать это:

tokenUserRelations[token] = req.body.email; 

так что я могу связать, какой пользователь точки маркера.

У меня возникло ощущение, что сохранение токена-> отношения с электронной почтой в глобальном объекте вызовут головные боли в будущем, особенно когда истекают токены/куки.

Есть ли лучший способ об этом? Мне нужно знать, какой пользователь указывает на токен JWT, чтобы я мог с ними сделать некоторую бизнес-логику.

спасибо.

ответ

1

Токен может содержать информацию обо всем, что вы хотите, эта информация зашифровывается вдоль токена.

Что вы можете сделать, это зашифровать идентификатор пользователя в токене, когда вы получаете запрос, дешифруете токен (который в любом случае выполняется при его проверке) и используют идентификатор пользователя как обычно.

Таким образом, если токен истекает, новый токен будет иметь одинаковый идентификатор пользователя, и ваш код не будет затронут.

Это то, что я сделал в одном из своих веб-приложений, и он отлично работал. Тем не менее, я использовал official jwt module

+0

Так я должен расшифровать токен каждый раз, когда запрос попадает в мои конечные точки сокета? Если да: A. Есть ли способ установить глобальное перед промежуточным программным обеспечением все мои конечные точки socket.io? B: Будет ли заметное влияние на производительность, поскольку дешифрование может быть задачей для процессора? – Aris

+1

Да, это то, как вы проверяете токен, а не запоминаете их на стороне сервера. Для экспресс-да, но я не знаю, для socket.io. Существует, но не более, чем другие схемы аутентификации. – DrakaSAN

+0

Разве вы не думаете, что могут быть разные подходы? Расшифровка и повторная проверка токена каждый раз звучат не очень хорошо, особенно с точки зрения производительности, потому что я получаю много вызовов сокетов. (Разработка игры, так что у меня много сокетов). Я думал, что все цели сокетов - это идентификация безопасного рукопожатия между обеими сторонами, поэтому все транзакции можно безопасно сделать без дополнительных контролей во время вызовов. Не уверен, что я ошибаюсь, поскольку я не знаком с программированием в реальном времени. – Aris

1

Вы ничего не показываете в своем коде о том, как создается или поддерживается tokenUserRelations, но как только я слышу «глобальный», у меня в голове появляется красный флаг.

Стандарт JWT включает концепцию вложения «претензий» в сам токен; вы уже делаете это с константой claims. Этот формат данных произволен и может быть доверен вашему приложению, пока общий JWT будет проверен. Обратите внимание, что вы хотите проверить JWT по каждому запросу. Таким образом, заполнение электронной почты в этом объекте претензий не просто прекрасное, это то, что делают большинство людей.

Как оповещение, вы должны быть осторожны, как вы устанавливаете свой «jwt.secret» прямо сейчас. Теперь у вас будет генерация нового при каждом запуске приложения, что означает, что: а) все ваши пользователи будут выходить из системы и должны повторно зарегистрироваться каждый раз, когда приложение перезагружается, и b) вы не можете использовать нескольких процессов или нескольких серверов, если вам нужно в будущем.

Лучше вытащить это из среды (например, env var), чем генерировать его при запуске приложения, если только вы просто не делаете этого для целей отладки.

+0

userRelations - это просто базовая хеш-таблица, где ключ - это токен, а значение - это электронная почта. Я был осторожен в размещении информации внутри токенов в целях безопасности, поэтому я хотел сохранить их на стороне сервера. Да, когда я перезапускаю приложение, токены становятся недействительными. С этого момента я сохраню его в своем .env. Итак, правильный/безопасный подход заключался бы в добавлении информации в объект 'Claim', проверяющий' socket.handshake.query.token' на каждый вызов сокета и дешифрующий токен для получения информации? – Aris

+0

Да, именно так были использованы токены JWT. – Paul

1

Добавляя к превосходным ответам выше, важно также, чтобы если вы решили сохранить свой файл jwt.secret в файле и вытащить его, когда загружается код, который вы не добавляете в свой репозиторий git (или какой-либо другой VCS). Убедитесь, что вы указали путь к jwt.secret в файле .gitignore. Затем, когда вы готовы развернуть свой производственный код, вы можете установить этот ключ как переменную среды, как было предложено. И у вас будет запись этого ключа в вашей локальной среде, если вам когда-нибудь понадобится его сбросить.

Использование JWT - отличный и удобный способ обеспечения безопасности вашего api, но важно следовать наилучшей практике.

+0

Я использую '.env'. Я думал, что секрет должен быть разным каждый раз, поскольку учебник, который я последовал, сделал это так. Я рад, что могу полагаться на '.env', потому что токены, которые были недействительны после перезагрузки, были большой проблемой. :) – Aris

+0

Определенно! Вы также можете установить токены, истекающие, проверив iat и принудительно переиздание, если оно есть. – alexi2

+0

Хорошо! Я буду помнить об этом. Поздравляю вас, папа, кстати. :) – Aris

Смежные вопросы