如何解码jwt令牌在javascript不使用一个库?

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

示例令牌:xxxxxxxxx.XXXXXXXX.xxxxxxxx

结果就是有效载荷:

{exp: 10012016 name: john doe, scope:['admin']}
472588 次浏览

你可以使用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 {
return JSON.parse(atob(token.split('.')[1]));
} catch (e) {
return null;
}
};

谢谢!

jwt的所有特性。IO不支持所有语言。在NodeJs中你可以使用

var decoded = jwt.decode(token);

我在jwt.io找到了这个代码,它工作得很好。

//this is used to parse base64
function url_base64_decode(str) {
var output = str.replace(/-/g, '+').replace(/_/g, '/');
switch (output.length % 4) {
case 0:
break;
case 2:
output += '==';
break;
case 3:
output += '=';
break;
default:
throw 'Illegal base64url string!';
}
var result = window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
try{
return decodeURIComponent(escape(result));
} catch (err) {
return result;
}
}

在某些情况下(某些开发平台),
(目前)最好的答案面临一个base64长度无效的问题 所以,我需要一个更稳定的方法

我希望这对你有所帮助。

@Peheje将工作,但你将有问题的unicode。 为了修复它,我使用https://stackoverflow.com/a/30106551/5277071上的代码;

let b64DecodeUnicode = str =>
decodeURIComponent(
Array.prototype.map.call(atob(str), c =>
'%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
).join(''))


let parseJwt = token =>
JSON.parse(
b64DecodeUnicode(
token.split('.')[1].replace('-', '+').replace('_', '/')
)
)




let form = document.getElementById("form")
form.addEventListener("submit", (e) => {
form.out.value = JSON.stringify(
parseJwt(form.jwt.value)
)
e.preventDefault();
})
textarea{width:300px; height:60px; display:block}
<form id="form" action="parse">
<textarea name="jwt">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkrDtGhuIETDs8OoIiwiYWRtaW4iOnRydWV9.469tBeJmYLERjlKi9u6gylb-2NsjHLC_6kZNdtoOGsA</textarea>
<textarea name="out"></textarea>
<input type="submit" value="parse" />
</form>

我使用这个函数根据回答来获得有效载荷,报头,exp(过期时间),iat(发出时间)

function parseJwt(token) {
try {
// Get Token Header
const base64HeaderUrl = token.split('.')[0];
const base64Header = base64HeaderUrl.replace('-', '+').replace('_', '/');
const headerData = JSON.parse(window.atob(base64Header));


// Get Token payload and date's
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
const dataJWT = JSON.parse(window.atob(base64));
dataJWT.header = headerData;


// TODO: add expiration at check ...




return dataJWT;
} catch (err) {
return false;
}
}


const jwtDecoded = parseJwt('YOUR_TOKEN') ;
if(jwtDecoded)
{
console.log(jwtDecoded)
}

由于nodejs环境中没有“window”对象, 我们可以使用以下代码行:

let base64Url = token.split('.')[1]; // token you get
let base64 = base64Url.replace('-', '+').replace('_', '/');
let decodedData = JSON.parse(Buffer.from(base64, 'base64').toString('binary'));

它非常适合我。希望能有所帮助。

根据这里的答案和在这里:

const dashRE = /-/g;
const lodashRE = /_/g;


module.exports = function jwtDecode(tokenStr) {
const base64Url = tokenStr.split('.')[1];
if (base64Url === undefined) return null;
const base64 = base64Url.replace(dashRE, '+').replace(lodashRE, '/');
const jsonStr = Buffer.from(base64, 'base64').toString();
return JSON.parse(jsonStr);
};

解码JSON Web令牌(JWT)的简单NodeJS解决方案

function decodeTokenComponent(value) {
const buff = new Buffer(value, 'base64')
const text = buff.toString('ascii')
return JSON.parse(text)
}


const token = 'xxxxxxxxx.XXXXXXXX.xxxxxxxx'
const [headerEncoded, payloadEncoded, signature] = token.split('.')
const [header, payload] = [headerEncoded, payloadEncoded].map(decodeTokenComponent)


console.log(`header: ${header}`)
console.log(`payload: ${payload}`)
console.log(`signature: ${signature}`)

基于GitHub - auth0/jwt-decode的答案。修改输入/输出,包括字符串分割和返回对象{header, payload, signature},这样你就可以传递整个令牌。

var jwtDecode = function (jwt) {


function b64DecodeUnicode(str) {
return decodeURIComponent(atob(str).replace(/(.)/g, function (m, p) {
var code = p.charCodeAt(0).toString(16).toUpperCase();
if (code.length < 2) {
code = '0' + code;
}
return '%' + code;
}));
}


function decode(str) {
var output = str.replace(/-/g, "+").replace(/_/g, "/");
switch (output.length % 4) {
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw "Illegal base64url string!";
}


try {
return b64DecodeUnicode(output);
} catch (err) {
return atob(output);
}
}


var jwtArray = jwt.split('.');


return {
header: decode(jwtArray[0]),
payload: decode(jwtArray[1]),
signature: decode(jwtArray[2])
};


};

你可以使用纯javascript atob()函数将token解码为字符串:

atob(token.split('.')[1]);

或者直接解析成json对象:

JSON.parse(atob(token.split('.')[1]));

阅读关于atob()btoa()内置javascript函数Base64编码和解码- Web api | MDN

function parseJwt(token) {
var base64Payload = token.split('.')[1];
var payload = Buffer.from(base64Payload, 'base64');
return JSON.parse(payload.toString());
}
let payload= parseJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
console.log("payload:- ", payload);

如果使用node,你可能需要使用缓冲包:

npm install buffer
var Buffer = require('buffer/').Buffer

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

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代码片段工具中使其可运行,但如果您运行该代码,大约会看到以下内容:

enter image description here

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

这允许你使用如下语法:

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

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

如果有人能想到任何对这段代码的低工作量、高价值的更改,请随意编辑我的回答,以造福next(person)

如果你使用Node.JS, 你可以这样使用本机Buffer模块:

const token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImp0aSI6ImU3YjQ0Mjc4LTZlZDYtNDJlZC05MTZmLWFjZDQzNzhkM2U0YSIsImlhdCI6MTU5NTg3NzUxOCwiZXhwIjoxNTk1ODgxMTE4fQ.WXyDlDMMSJAjOFF9oAU9JrRHg2wio-WolWAkAaY3kg4';
const tokenDecodablePart = token.split('.')[1];
const decoded = Buffer.from(tokenDecodablePart, 'base64').toString();
console.log(decoded)

你就可以开始了:-)

在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,你可以使用最小的import { decode as base64Decode } from 'jose/util/base64url'并将new Uint8Array(Buffer.from(input, 'base64'))替换为base64Decode(input)。这样代码就可以在浏览器和Node.js中正常工作。

如果你正在使用打印稿 vanilla JavaScript,这里有一个零依赖,准备在你的项目简单函数中复制粘贴(基于@Rajan Maharjan的回答)。

这个答案特别好,不仅因为它不依赖于任何npm模块,还因为它不依赖于任何node.js内置模块(如Buffer),而其他一些解决方案正在使用这些模块,当然会在浏览器中失败(除非是填充的,但首先没有理由这样做)。此外JSON。解析可能会在运行时失败,这个版本(尤其是在Typescript中)将强制处理它。JSDoc注释将使将来的代码维护者感激不尽。:)

/**
* Returns a JS object representation of a Javascript Web Token from its common encoded
* string form.
*
* @template T the expected shape of the parsed token
* @param {string} token a Javascript Web Token in base64 encoded, `.` separated form
* @returns {(T | undefined)} an object-representation of the token
* or undefined if parsing failed
*/
export function getParsedJwt<T extends object = { [k: string]: string | number }>(
token: string,
): T | undefined {
try {
return JSON.parse(atob(token.split('.')[1]))
} catch {
return undefined
}
}

为了完成,这里还有一个普通的javascript版本:

/**
* Returns a JS object representation of a Javascript Web Token from its common encoded
* string form.
*
* @param {string} token a Javascript Web Token in base64 encoded, `.` separated form
* @returns {(object | undefined)} an object-representation of the token
* or undefined if parsing failed
*/
export function getParsedJwt(token) {
try {
return JSON.parse(atob(token.split('.')[1]))
} catch (error) {
return undefined
}
}

一个es模块友好的简化版jwt-decode.js

function b64DecodeUnicode(str) {
return decodeURIComponent(
atob(str).replace(/(.)/g, function (m, p) {
var code = p.charCodeAt(0).toString(16).toUpperCase();
if (code.length < 2) {
code = "0" + code;
}
return "%" + code;
})
);
}


function base64_url_decode(str) {
var output = str.replace(/-/g, "+").replace(/_/g, "/");
switch (output.length % 4) {
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw "Illegal base64url string!";
}


try {
return b64DecodeUnicode(output);
} catch (err) {
return atob(output);
}
}


export function jwtDecode(token, options) {
options = options || {};
var pos = options.header === true ? 0 : 1;
try {
return JSON.parse(base64_url_decode(token.split(".")[pos]));
} catch (e) {
console.log(e.message);
}
}

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

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

你可以定义&使用这个函数:

jwtDecode = b => JSON.parse(Buffer.from(b.split('.')[1], 'base64').toString('binary'));