---
title: "在微信小程序中解码与验证 JWT Payload"
date: 2019-01-09T18:04:59.000Z
author: Z.SHINCHVEN
tags: [JWT, JSONWebToken, 微信小程序, Base64]
canonical: https://atlassc.net/2019/01/10/decode-jwt-payload-in-wechat-miniprogram
---
## 快速开始

在微信小程序中，你可以使用内置的 `wx.base64ToArrayBuffer` 快速解码 JWT Payload：

```javascript
let token = "YOUR_JWT_TOKEN";
let payloadEncoded = token.split('.')[1];
let buffer = wx.base64ToArrayBuffer(payloadEncoded);
let payloadDecoded = String.fromCharCode.apply(null, new Uint8Array(buffer));
let payload = JSON.parse(payloadDecoded);

console.log(payload);
```

## JWT 简介

JSONWebToken (JWT) 常用于 RESTful API 的认证。JWT 包含一个使用 Base64 编码的 `payload` 部分，其中存储了可以在客户端使用的身份信息和 token 有效期等数据。

## 其他环境下的解码方式

### Node.js

在 Node.js 中解 JWT 的 payload 最简单，可以直接使用 [jsonwebtoken 库](https://www.npmjs.com/package/jsonwebtoken) 中的 `decode()` 函数：

```javascript
const jwt = require('jsonwebtoken');
let token = "YOUR_TOKEN";
let payload = jwt.decode(token);
```

### Web 前端

在 Web 前端中要解 JWT 的 payload [也很简单](https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript)：

```javascript
var base64Url = token.split('.')[1];
var base64 = base64Url.replace('-', '+').replace('_', '/');
var payload = JSON.parse(window.atob(base64));
```

实现原理是：

1.  将 token 中通过 `.` 分割取中间（下标 1）的字符串，并替换相应字符；
2.  使用 [window.atob()](https://www.w3schools.com/jsref/met_win_atob.asp) 函数将 base64 进行解码；
3.  最后将解除来的 JSON string 转成 JSON Object。

经过检查 `jsonwebtoken` 库的源码，发现也是这个原理，只是解码 base64 的方式不同。

## 微信小程序中的实现原理

根据上面的思路，要实现在微信小程序中解 JWT 的 payload，只需要改用微信小程序中内置的 base64 库来解即可。因为小程序不支持 `window` 对象和 `atob` 方法，我们需要使用 `wx.base64ToArrayBuffer`。

## 封装工具类

为了在微信小程序端方便的解码和验证 JWT，我编写了一个工具类 `JWTPayload`：

```javascript
/**
 * @author ShinChven Zhang
 * 在微信小程序中解jwt中的payload，并进行有效验证。
 */
class JWTPayload {

  /**
   * encoded JSONWebToken
   */
  constructor(token) {
    this.payload = this.decodePayload(token);
  }

  /**
   * 解token
   * token JSONWebToken
   * return payload object
   */
  decodePayload(token) {
    try {
      let payloadEncoded = token.split('.')[1];
      let buffer = wx.base64ToArrayBuffer(payloadEncoded);
      let payloadDecoded = String.fromCharCode.apply(null, new Uint8Array(buffer));
      return JSON.parse(payloadDecoded)
    } catch (err) {
      console.error(err);
      return null
    }
  }

  /**
   * 验证是否有效
   * return boolean
   */
  isValid() {
    try{
      if (this.payload && this.payload.exp) {
        let timestamp = Date.parse(new Date());
        timestamp = timestamp / 1000;
        console.log(timestamp)
        return this.payload.exp > timestamp;
      }
    }catch(err){
      console.error(err);
    }
    return false;
  }
}

module.exports = JWTPayload
```

**使用方法：**

```javascript
let jwt = new JWTPayload(token);
if (jwt.isValid()){
    console.log(jwt.payload);
}
```
