zoukankan      html  css  js  c++  java
  • 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 就算完成了。。。。

  • 相关阅读:
    告别ThinkPHP6的异常页面, 让我们来拥抱whoops吧
    ThinkPHP6 上传图片代码demo
    【ThinkPHP6:从TP3升级到放弃】1. 前言及准备工作
    PHP数字金额转换大写金额
    提高PHP开发效率, PhpStorm必装的几款插件
    5分钟弄懂Docker!
    GitHub 上排名前 100 的 IOS 开源库简介
    GitHub 上排名前 100 的 Android 开源库简介
    android线程消息传递机制——Looper,Handler,Message
    Android Activity:四种启动模式,Intent Flags和任务栈
  • 原文地址:https://www.cnblogs.com/hl1223/p/13024954.html
Copyright © 2011-2022 走看看