const secretKey = 'bbcbc743fa6297659f2505bd4958ba8eb2cb16a4baecab4f88eae3f4665a4601';
async function test() {
const jwt = await getJWT('qinleilxl@outlook.com');
console.log('>>>>>> jwt: ', jwt);
const [err, isValid] = await verifyJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJxaW5sZWlseGxAZ21haWwuY29tIiwiZXhwaXJlIjoxNjk3MDY4ODAwMDAwLCJyYW5kb20iOiI1NTA3ODU0NTc5NzMyMTBlZDYzYTkzOWRiMzk5N2JkYyJ9.3bXgftD90TUSfzduUo7VRzG4zaUm10A654DgoPGXUw=", secretKey);
if (err) {
console.log('>>>>> err: ', err);
}
console.log('>>>>> isValid: ', isValid);
}
test();
function verifyJWT(jwt, secretKey) {
const [header, payload, signature] = jwt.split('.');
const decodedHeader = atob(header);
const decodedPayload = atob(payload);
const headerObj = JSON.parse(decodedHeader);
const algorithm = headerObj.alg;
const encodedSignature = btoa(signature);
const dataToVerify = `${header}.${payload}`;
const encoder = new TextEncoder();
const dataToVerifyBuffer = encoder.encode(dataToVerify);
return crypto.subtle.importKey(
'raw',
encoder.encode(secretKey),
{ name: 'HMAC', hash: { name: 'SHA-256' } },
false,
['verify']
)
.then((importedKey) => {
return crypto.subtle.verify(
'HMAC',
importedKey,
new Uint8Array(atob(signature).split('').map(char => char.charCodeAt(0))),
new Uint8Array(dataToVerifyBuffer).buffer,
);
})
.then((isValid) => {
return [null, isValid];
})
.catch((error) => {
console.error('验证 JWT 签名时出错:', error.message);
return [error.message, false];
});
}
function decodeJWT(jwt) {
const parts = jwt.split('.');
if (parts.length !== 3) {
throw new Error('Invalid JWT format');
}
const encodedPayload = parts[1];
const decodedPayload = atob(encodedPayload);
const payloadObj = JSON.parse(decodedPayload);
return payloadObj;
}
async function getJWT(userId) {
const now = new Date();
const expireDay = customAdd(now, 1, 'day');
const expireTime = getStartOfDay(expireDay).getTime();
const payload = {
userId,
expire: expireTime,
random: generateRandom32BitString()
};
const header = {
alg: 'HS256',
typ: 'JWT',
};
const encodedHeader = btoa(JSON.stringify(header));
const encodedPayload = btoa(JSON.stringify(payload));
const dataToSign = `${encodedHeader}.${encodedPayload}`;
const signature = await signWithHmacSHA256(dataToSign, secretKey);
const jwt = `${dataToSign}.${signature}`;
return jwt;
}
function customAdd(oldDate, amount, unit) {
if (!isValidDate(oldDate)) {
throw new Error('Invalid date');
}
const date = new Date(oldDate);
switch (unit) {
case 'year':
date.setFullYear(date.getFullYear() + amount);
break;
case 'month':
date.setMonth(date.getMonth() + amount);
break;
case 'day':
date.setDate(date.getDate() + amount);
break;
case 'hour':
date.setHours(date.getHours() + amount);
break;
case 'minute':
date.setMinutes(date.getMinutes() + amount);
break;
case 'second':
date.setSeconds(date.getSeconds() + amount);
break;
default:
throw new Error(`Invalid unit: ${unit}`);
}
return date;
}
function isValidDate(date) {
return date instanceof Date && !isNaN(date);
}
function getStartOfDay(date) {
date.setHours(0, 0, 0, 0);
return date;
}
async function signWithHmacSHA256(data, key) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const keyBuffer = encoder.encode(key);
const importedKey = await crypto.subtle.importKey(
'raw',
keyBuffer,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signatureBuffer = await crypto.subtle.sign('HMAC', importedKey, dataBuffer);
const verifyImportedKey = await crypto.subtle.importKey(
'raw',
encoder.encode(secretKey),
{ name: 'HMAC', hash: { name: 'SHA-256' } },
false,
['verify']
)
const signatureArray = Array.from(new Uint8Array(signatureBuffer));
const signatureHex = signatureArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
const signature = btoa(String.fromCharCode.apply(null, signatureArray));
return signature;
}
function generateRandom32BitString() {
const randomBytes = new Uint8Array(16);
crypto.getRandomValues(randomBytes);
let hexString = '';
for (let i = 0; i < randomBytes.length; i++) {
let hex = randomBytes[i].toString(16);
if (hex.length === 1) {
hex = '0' + hex;
}
hexString += hex;
}
return hexString;
}
console