«В предыдущей статье я объяснил, как можно реализовать авторизацию и аутентификацию через JWT с использованием симметричных алгоритмов, таких как HS256. Теперь я попытаюсь объяснить асимметричный подход (RS256).
Вы можете спросить: зачем нам нужен другой способ создания JWT? Что ж, этот ответ может помочь вам понять, почему.
Рабочий процесс использования JWT остается таким же, как и при симметричном подходе. Единственное отличие состоит в том, что теперь мы не используем secret
для создания и проверки токена доступа. Вместо этого нам нужна пара открытых/закрытых ключей RSA. Мы используем закрытый ключ только для создания JWT, а открытый ключ — только для его проверки. Таким образом, вам не нужно хранить какую-то секретную информацию для проверки токенов. Вы можете сгенерировать такую пару ключей, используя следующие команды:
openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -outform PEM -pubout -out public.pem
Итак, для генерации JWT мы делаем следующее
const encodedHeaderInBase64 = base64UrlEncodeJSON(header) const encodedPayloadInBase64 = base64UrlEncodeJSON(payload) const encodedSignatureInBase64 = generateSignature(`${encodedHeaderInBase64}.${encodedPayloadInBase64}`, privateKey) const token = `${encodedHeaderInBase64}.${encodedPayloadInBase64}.${encodedSignatureInBase64}`
Где generateSignature
в данном случае
const crypto = require('crypto') function generateSignature (str, privateKey) { const sign = crypto.createSign('RSA-SHA256') sign.update(str) return sign.sign(privateKey, 'base64') .replace(/\+/g, '-') .replace(/\//g, '_') }
И base64UrlEncodeJSON
такой же.
function base64UrlEncodeJSON (json) { return Buffer.from( JSON.stringify(json) ).toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') }
И для проверки мы можем использовать следующую функцию
// Returns true if token is valid, otherwise returns false function isValid (token, secret) { const parts = token.split('.') const header = base64UrlDecodeToJSON(parts[0]) const payload = base64UrlDecodeToJSON(parts[1]) if (header.alg !== 'RS256' || header.typ !== 'JWT') { return false } const signature = parts[2] const exp = payload.exp if (exp) { if (exp < new Date().getTime()) { return false } } const verify = crypto.createVerify('RSA-SHA256') verify.update(unescape(`${parts[0]}.${parts[1]}`)) return verify.verify(publicKey, signature, 'base64') } function base64UrlDecodeToJSON (str) { return JSON.parse( Buffer.from( unescape(str), 'base64' ).toString('utf8') ) } function unescape (str) { return str.replace(/-/g, '+').replace(/_/g, '/') }
Для тестирования вашего токена доступа вы также можете использовать эту услугу. Просто измените свойство alg
на RS256
.
Кроме того, я только что выпустил cutie-jwt. Итак, если вы хотите использовать JWT в декларативном стиле, вам обязательно стоит попробовать.
Рекомендации