Я пытаюсь реализовать свою собственную аутентификацию, используя токены JWT. Я генерирую токены jwt при загрузке Java Spring.
Я использую этот веб-сайт для создания строки в кодировке Base64, которая будет использоваться в качестве секрета jwt: https://www.devglan.com/online-tools/hmac-sha256-online?ref=blog.tericcabrel.com
Это соответствующий загрузочный код Spring:
private Key getSignInKey() {
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
Jwts
.builder()
.setClaims(extraClaims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
.compact();
Всё работает, проблема не здесь. Проблема возникает на стороне nextjs, где я пытаюсь проверить токен jwt, который я получаю из API после входа в систему:
export async function verifyAuth() {
const token = cookies().get('user-token')
if (!token) {
return null
}
const jwtSecretKey = getJwtSecretKey()
const { payload } = await jwtVerify(token.value, new TextEncoder().encode(jwtSecretKey))
return payload as JwtPayload
}
Это продолжает вызывать следующее исключение, хотя я использую тот же секретный ключ, сгенерированный веб-сайтом выше (getJwtSecretKey просто возвращает переменную env из .env, а я использую jose):
digest: "3414803446"
⨯ JWSSignatureVerificationFailed: signature verification failed
at async verifyAuth (./lib/auth.ts:74:25)
at async Home (./app/page.tsx:11:18)
Что я здесь делаю не так?
@JaromandaX да, getJwtSecretKey получает правильный секрет, он используется на серверной стороне так же, как secretKey
Значение — это строка в кодировке Base64, которую я получил с веб-сайта. Я понимаю вашу точку зрения: поскольку я декодирую ключ на сервере, мне также следует декодировать его на клиенте, а не кодировать, верно?
понятия не имею... но BASE64.decode
и TextEncoder().encode
не приводят к одному и тому же результату... возможно, вам нужно везде декодировать base64 (не знаю, что вы подразумеваете под клиентом, если это в браузере, вы используете JWT неправильный)
Почему вы используете new TextEncoder().encode(jwtSecretKey)
? Это выглядит неправильно.
Кстати, getSignInKey
надо писать getSigningKey
Секрет, передаваемый в процессе подписи, декодируется из строки base64, прежде чем использоваться в качестве секрета подписи. Вы должны сделать то же самое, прежде чем передавать секрет jose
, в противном случае new TextEncoder().encode(jwtSecretKey)
просто использует закодированные байты в качестве секрета.
Это в Node.js
const secret = Buffer.from(jwtSecretKey, 'base64')
Было бы эквивалентно
keyBytes = Decoders.BASE64.decode(secretKey);
возможно,
getJwtSecretKey()
не получает правильный секрет - вы говорите, что да, но, возможно, это не так - какBASE64.decode(secretKey)
то же самое, что иnew TextEncoder().encode(jwtSecretKey)
... еслиsecretKey
иjwtSecretKey
имеют одно и то же значение по основанию 64, то это может объяснить это