简体   繁体   English

如何在不使用库的情况下在 javascript 中解码 jwt 令牌?

[英]How to decode jwt token in javascript without using a library?

How can I decode the payload of JWT using JavaScript?如何使用 JavaScript 解码 JWT 的有效负载? Without a library.没有图书馆。 So the token just returns a payload object that can consumed by my front-end app.所以令牌只返回一个负载对象,我的前端应用程序可以使用它。

Example token: xxxxxxxxx.XXXXXXXX.xxxxxxxx示例令牌: xxxxxxxxx.XXXXXXXX.xxxxxxxx

And the result is the payload:结果是有效载荷:

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

Working unicode text JWT parser function:工作 unicode 文本 JWT 解析器功能:

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

    return JSON.parse(jsonPayload);
};

Simple function with try - catch带有 try-catch 的简单功能

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

Thanks!谢谢!

You can use jwt-decode , so then you could write:您可以使用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']}*/

you can use pure javascript atob() function to decode token into a string:您可以使用纯 javascript atob()函数将令牌解码为字符串:

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

or parse directly it into a json object:或者直接解析成json对象:

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

read about atob() and btoa() built-in javascript functions Base64 encoding and decoding - Web APIs |阅读关于atob()btoa()内置 JavaScript 函数Base64 编码和解码 - Web API | MDN . 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);

If using node, you might have to use buffer package:如果使用节点,您可能必须使用缓冲包:

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

As "window" object is not present in nodejs environment, we could use the following lines of code :由于 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'));

It's working for me perfectly.它非常适合我。 Hope it helps.希望它有帮助。

@Peheje will work, but you will have problem with unicode. @Peheje 会工作,但你会遇到 unicode 问题。 To fix it I use the code on https://stackoverflow.com/a/30106551/5277071 ;为了修复它,我使用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>

I use this function to get payload , header , exp(Expiration Time), iat (Issued At) based on this answer我使用此函数根据答案获取有效负载、标头、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)
}

If you're using Typescript or vanilla JavaScript , here's a zero-dependency, ready to copy-paste in your project simple function (building on @Rajan Maharjan 's answer).如果您使用的是Typescriptvanilla JavaScript ,这是一个零依赖项,可以在您的项目简单函数中复制粘贴(基于 @Rajan Maharjan 的回答)。

This answer is particularly good, not only because it does not depend on any npm module, but also because it does not depend an any node.js built-in module (like Buffer ) that some other solutions here are using and of course would fail in the browser (unless polyfilled, but there's no reason to do that in the first place).这个答案特别好,不仅因为它不依赖于任何 npm 模块,还因为它不依赖于这里的其他一些解决方案正在使用的任何 node.js 内置模块(如Buffer ),当然会失败在浏览器中(除非 polyfill,但首先没有理由这样做)。 Additionally JSON.parse can fail at runtime and this version (especially in Typescript) will force handling of that.此外 JSON.parse 可能会在运行时失败,这个版本(尤其是在 Typescript 中)将强制处理它。 The JSDoc annotations will make future maintainers of your code thankful. 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
  }
}

For completion, here's the vanilla javascript version too:为了完成,这里也是香草 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
  }
}

I found this code at jwt.io and it works well.我在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;
  }
}

In some cases(certain development platforms),在某些情况下(某些开发平台),
the best answer(for now) faces a problem of invalid base64 length.最佳答案(目前)面临着 base64 长度无效的问题。
So, I needed a more stable way.所以,我需要一种更稳定的方式。

I hope it would help you.我希望它会帮助你。

all features of jwt.io doesn't support all languages. jwt.io 的所有功能并不支持所有语言。 In NodeJs you can use在 NodeJs 中,您可以使用

var decoded = jwt.decode(token);

If you use Node.JS, You can use the native Buffer module by doing :如果您使用 Node.JS,您可以通过执行以下操作来使用本机 Buffer 模块:

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

And you're good to go :-)你很高兴去:-)

Simple NodeJS Solution for Decoding a JSON Web Token (JWT)用于解码 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}`)

Answer based from GitHub - auth0/jwt-decode .基于GitHub 的答案- auth0/jwt-decode Altered the input/output to include string splitting and return object { header, payload, signature } so you can just pass the whole token.更改输入/输出以包括字符串拆分和返回对象 { 标头、有效负载、签名},因此您可以只传递整个令牌。

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])
        };

    };

Here is a more feature-rich solution I just made after studying this question:这是我在研究这个问题后刚刚制作的功能更丰富的解决方案:

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.',
        };
    }
};

Here's some usage samples:以下是一些使用示例:

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
}

I wasn't able to make that runnable in StackOverflow code snippet tool, but here's approximately what you would see if you ran that code:我无法在 StackOverflow 代码片段工具中使其可运行,但是如果您运行该代码,您将看到的大致内容如下:

在此处输入图片说明

I made the parseJwt function always return an object (to some degree for static-typing reasons).我让parseJwt函数总是返回一个对象(在某种程度上由于静态类型的原因)。

This allows you to utilize syntax such as:这允许您使用语法,例如:

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

Then you can test at run-time for specific types of errors and avoid any naming collision.然后您可以在运行时测试特定类型的错误并避免任何命名冲突。

If anyone can think of any low effort, high value changes to this code, feel free to edit my answer for the benefit of next(person) .如果有人能想到对此代码进行任何低努力、高价值的更改,请随时编辑我的答案,以造福next(person)

In Node.js (TypeScript):在 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 };
}

With jose by panva on GitHub , you could use the minimal import { decode as base64Decode } from 'jose/util/base64url' and replace new Uint8Array(Buffer.from(input, 'base64')) with base64Decode(input) .使用GitHub 上 panva 的jose ,您可以使用最小的import { decode as base64Decode } from 'jose/util/base64url'并将new Uint8Array(Buffer.from(input, 'base64'))替换为base64Decode(input) Code should then work in both browser and Node.js.然后代码应该可以在浏览器和 Node.js 中运行。

Both Guy and Peheje already answered the question. Guy和Peheje都已经回答了这个问题。 For a total beginner like me it was helpful to also have the import line defined in the example. 对于像我这样的新手来说,在示例中定义导入行也很有帮助。

Also it took me some minutes to figure out that the token is the full set of credentials that gets posted back (the whole JWT token, not just the idToken part of it). 另外,我花了几分钟的时间才弄清楚令牌是要回发的完整凭据的集合(整个JWT令牌,而不仅仅是IDToken的一部分)。 Straightforward once you know it.. 一旦知道就直接

 import jwt_decode from 'jwt-decode'; var token = 'eyJ0eXAiO.../// jwt token'; var decoded = jwt_decode(token); /*{exp: 10012016 name: john doe, scope:['admin']}*/ 

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

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

Based on answers here and here :基于此处和此处的答案:

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);
};

An es-module friendly simplified version of jwt-decode.js jwt-decode.js的 es-module 友好的简化版本

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);
  }
}

您可以定义和使用这个 liner func:

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

Running Javascript node.js express I had to first install the package as follows: 运行Javascript node.js express,我必须首先按照以下步骤安装软件包:

npm install jwt-decode --save

then in my app.js code get the package: 然后在我的app.js代码中获取软件包:

const jwt_decode = require('jwt-decode');

Then run the code: 然后运行代码:

let jwt_decoded = jwt_decode(jwt_source);

Then the magic: 然后魔术:

console.log('sub:',jwt_decoded.sub);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM