如何使用JavaScript解码JWT的有效负载?没有图书馆。令牌只返回一个有效负载对象,前端应用可以使用它。

示例令牌:xxxxxxxxx.XXXXXXXX.xxxxxxxx

结果就是有效载荷:

{exp: 10012016 name: john doe, scope:['admin']}

当前回答

如果使用node.js 16或更高版本,可以使用内置的base64url编码器/解码器。

let payload = JSON.parse(Buffer.from(token.split(".")[1], "base64url"));

其他回答

在Node.js (TypeScript)中:

import { TextDecoder } from 'util';

function decode(jwt: string) {
    const { 0: encodedHeader, 1: encodedPayload, 2: signature, length } = jwt.split('.');

    if (length !== 3) {
        throw new TypeError('Invalid JWT');
    }

    const decode = (input: string): JSON => { return JSON.parse(new TextDecoder().decode(new Uint8Array(Buffer.from(input, 'base64')))); };

    return { header: decode(encodedHeader), payload: decode(encodedPayload), signature: signature };
}

与jose在GitHub上的panva,你可以使用最小的导入{解码为base64Decode}从'jose/util/base64url'和替换新的Uint8Array(Buffer.from(输入,'base64'))与base64Decode(输入)。这样代码就可以在浏览器和Node.js中正常工作。

你可以使用jwt-decode,这样你就可以这样写:

import jwt_decode from 'jwt-decode';

var token = 'eyJ0eXAiO.../// jwt token';

var decoded = jwt_decode(token);
console.log(decoded);
/*{exp: 10012016 name: john doe, scope:['admin']}*/

注意:这并不验证签名,它只是从令牌中提取JSON有效负载,这可能已经被篡改了。

浏览器

unicode文本JWT解析器功能:

function parseJwt (token) {
    var base64Url = token.split('.')[1];
    var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
    var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));

    return JSON.parse(jsonPayload);
}

JWT使用base64url (RFC 4648§5),因此仅使用atob(使用base64)是不够的。

node . js

function parseJwt (token) {
    return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
}

下面是我在研究这个问题后提出的一个功能更丰富的解决方案:

const parseJwt = (token) => {
    try {
        if (!token) {
            throw new Error('parseJwt# Token is required.');
        }

        const base64Payload = token.split('.')[1];
        let payload = new Uint8Array();

        try {
            payload = Buffer.from(base64Payload, 'base64');
        } catch (err) {
            throw new Error(`parseJwt# Malformed token: ${err}`);
        }

        return {
            decodedToken: JSON.parse(payload),
        };
    } catch (err) {
        console.log(`Bonus logging: ${err}`);

        return {
            error: 'Unable to decode token.',
        };
    }
};

下面是一些使用示例:

const unhappy_path1 = parseJwt('sk4u7vgbis4ewku7gvtybrose4ui7gvtmalformedtoken');
console.log('unhappy_path1', unhappy_path1);

const unhappy_path2 = parseJwt('sk4u7vgbis4ewku7gvtybrose4ui7gvt.malformedtoken');
console.log('unhappy_path2', unhappy_path2);

const unhappy_path3 = parseJwt();
console.log('unhappy_path3', unhappy_path3);

const { error, decodedToken } = parseJwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c');
if (!decodedToken.exp) {
    console.log('almost_happy_path: token has illegal claims (missing expires_at timestamp)', decodedToken);
    // note: exp, iat, iss, jti, nbf, prv, sub
}

我无法在StackOverflow代码片段工具中使其可运行,但如果您运行该代码,大约会看到以下内容:

我让parseJwt函数总是返回一个对象(在某种程度上是出于静态类型的原因)。

这允许你使用如下语法:

const { decodedToken, error } = parseJwt(token);

然后,您可以在运行时测试特定类型的错误,并避免任何命名冲突。

如果有人能想到对这段代码进行任何低工作量、高价值的修改,请随意编辑我的答案,以供下一个人参考。

简单的功能与试接

const parseJwt = (token) => {
  try {
    return JSON.parse(atob(token.split('.')[1]));
  } catch (e) {
    return null;
  }
};

谢谢!