NodeJS 基于 JWT 实现身份验证(token、自动登陆)

JWT 简单的原理介绍

JWT(Json Web Token)是一种身份验证及授权方案,简单的说就是调用端调用 api 时,附带上一个由 api 端颁发的 token,以此来验证调用者的授权信息。

通过一种加密规则(如 HS256)+ secret 生成一串字符串(token),token 字符串中一般含有过期时间和签名信息,根据签名和过期时间,就可以判断当前 token 是否有效。

// newToken是根据 'jwt_secret' 生成的, jws.verify用于校验当前token是否是根据当前secret生成的
console.log(jws.verify(newToken, 'HS256', 'jwt_secret')); // true
console.log(jws.verify(newToken, 'HS256', '-=-=-=')); // false

无论使用哪个 secret 生成的 token,都是可以解析到 payload 的内容的,仅仅只是签名不同,
payload 的常见内容:

{
  uuid: "3455445-acuya7skeasd-iue7",  // token的有效内容
  phone: 133409899625,    // token的有效内容
  expires: 1591066434678, // token的过期时间
},[signature]

根据 expires 判断 token 是否过期,根据 signature 判断当前 token 是否时本人创建,根据这两点就可以判断 token 是否有效了。

更详细的介绍,可参考:https://jwt.io/

NodeJS 中如何应用 JWT

1. 安装 jsonwebtoken

npm install jsonwebtoken --save

PS: 也可以安装 jws,jsonwebtoken 是基于 jws 进行封装的,简化了使用方式。

2.封装 JWT 函数

import jsonwebtoken from 'jsonwebtoken';
const secret = 'test_key';

export default class JWT {
  public static generate(value: any, expires = '7 days'): string { // value 为传入值, expires为过期时间,这两者都会在token字符串中题先
    try {
      return jsonwebtoken.sign(value, secret, { expiresIn: expires });
    } catch (e) {
      console.error('jwt sign error --->', e);
      return '';
    }
  }

  public static verify(token: string) {
    try {
      return jsonwebtoken.verify(token, secret); // 如果过期将返回false
    } catch (e) {
      console.error('jwt verify error --->', e);
      return false;
    }
  }
}

测试 JWT 方法,开发中建议使用 Jest 等工具写点单元测试,这里就简化了....

const payload = {
  uuid: '3455445-acuya7skeasd-iue7',
  phone: 133409899625,
};
const token = JWT.generate(payload, '12s');
const info = JWT.verify(token);
console.log(token);
console.log(info);
setTimeout(() => {
  console.log('检验过期token');
  const info2 = JWT.verify(token);
  console.log(info2); // false
}, 13000);

/* 
  控制台打印:
  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiMzQ1NTQ0NS1hY3V5YTdza2Vhc2QtaXVlNyIsInBob25lIjoxMzM0MDk4OTk2MjUsImlhdCI6MTU5MDk5MDQwOSwiZXhwIjoxNTkxMDc2ODA5fQ.VEjIlQFEw4arU7jR54M6MYR7KMDx-VAlX_CcfmusKeU
  {
    uuid: '3455445-acuya7skeasd-iue7', // 传入的数据
    phone: 133409899625, // 传入的数据
    iat: 1590990409,
    exp: 1591076809  // 过期时间,不需要我们进行判断jsonwebtoken会帮我们进行过期校验,如果过期会返回false
  } 
*/

3. 封装自动校验的中间件

import { Context, Next } from 'koa';
import { JWT } from '../utils';

const Auth = async (ctx: Context, next: Next) => {
  const { authorization = '' } = ctx.request.header;
  const token = authorization.replace('Bearer ', '');
  const info = JWT.verify(token);
  if (info) {
    ctx.state.info = info; // 将信息存放到 state 中
  } else {
    ctx.throw(401, 'token error');
  }
  await next();
};

export default Auth;

4. 在 router 中使用

import Router from 'koa-router';
import UserController from '../controllers/user';
import Auth from '../middleware/auth'

const router = new Router<DefaultState, Context>({prefix: '/v1.0'});

router.post("/check", Auth, UserController.check); //只有通过 Auth 检测,才会进入 check 函数
router.post("/sendOTP", UserController.sendOTP);

export default router;

5. 在 Controller 中获取校验后的信息

...
async check(ctx: Context) {
  const { mobile, uuid } = ctx.state.info; // 获取 Auth 中传递的数据
  const result = await getInfo(uuid); // 获取数据库中的用户信息,getInfo 是封装的公用方法,这里旧暂略了
  const token = JWT.generate({ mobile, uuid }, '1d'); // 更新 token 时间(生成一条新的 token,旧的 token 任然是可以使用的)
  const data = Object.assign({}, result, { token });
  ctx.body = {
    status:200,
    message: 'Success',
    result: data
  }
}
...

6. 前端传递 token

前端使用 axios 进行数据发送

import axios from 'axios';
axios.defaults.withCredentials = true;

// 将 token 放到拦截器里面处理
axios.interceptors.request.use(function (config) {
  const requestToken = getCookie('token'); // 获取我们存储的 token
  config.headers['Authorization'] = 'Bearer ' + requestToken; // 将 token 放到 header 里面
  config.headers.post['Content-Type'] = 'application/json';
  config.timeout = 60000;
  return config;
});

至此,NodeJS中使用 JWT 就算完成了。。。。

posted @ 2020-06-01 14:18  啤酒煮鸡蛋  阅读(9783)  评论(0编辑  收藏  举报