热搜:fiddler git ip 代理 m1
历史搜索

Node.js中使用JWT、localStorage、Cookie校验用户信息

游客2024-08-06 09:30:01
目录文章目录
  1. 一. 概念
  2. 二. JWT 的生成与使用
  3. 三. 应用场景
  4. 结语

本文分别站在了客户端(React.js)与服务端(Node.js)的角度,总结了整个用户校验过程各自的操作。在 Node.js 中使用 JWT、localStorage 和 Cookie 校验用户信息是一种常见的做法。JWT(JSON Web Token)是一种基于 JSON 的开放标准,用于在各方之间安全地传输信息。它由头部、载荷和签名组成,其中载荷包含有关用户的信息和其他数据。在服务端,首先需要验证 JWT 的合法性和有效性,通过验证签名是否正确以及验证过期时间来确保 Token 的有效性。校验过程包括解析 JWT、比较签名、检查过期时间等步骤。如果验证通过,可以从 JWT 中获取用户信息,并将用户信息放入请求对象中,供后续操作使用。

一. 概念

1.1 localStorage 和 Cookie

都是存储数据的方式

  • localStorage:储存在客户端(浏览器)本地
  • Cookie:存储在服务端,安全性更高。(是一个 HTTP 请求标头,由服务器通过 Set-Cookie 设置,存储到客户端的 HTTP cookie

1.2 Token/JWT 和 SessionId

都是用户信息标识

  • Token:一个通用术语,是代表用户身份的字符串。它通常由服务器在用户成功登录后生成,并在用户进行后续请求时发送给服务器以验证其身份。
  • JWT(JSON Web Token):一种特殊的 Token。由三部分组成的字符串:Header(令牌类型和签名算法)、Payload(用户信息)、Signature 组成
  • SessionId:用来识别和追踪用户会话的一串唯一的字符

本文主要讲 JWT

二. JWT 的生成与使用

安装 JWT 库,官网链接:点击这里

2.1 安装 JWT 库

npm i jsonwebtoken

2.2 登录时生成 JWT

const jwt = require('jsonwebtoken');

const login = async (req, res) => {
   // ...登录成功后
   
   const token = jwt.sign(
      { userId: <userId>, username: <username> }, // 填入想存储的用户信息
      process.env.JWT_SECRET,                     // 秘钥,可以为随机一个字符串
      {
         expiresIn: "7d",                         // 其他选项,如过期时间
      }
   );
   
   // ...
};

接着就是选择存储方式:

  1. 将 token 返回到客户端让客户端存储在 localStorage;
  2. 将 token 存储在服务端 Cookie。

2.3 调用其他请求时验证 Token

// 验证的中间件

const authToken = async (req, res, next) => {
  
  // ... 根据存储方式拿到 token
  const token = "your_token"
  
   try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET); // 传入 token 和秘钥
      // 拿到解出来的 { userId, username }
      // ... 进一步从数据库中判断这个用户信息是否存在
      // 将信息挂载 req.user 中供后续接口使用
      req.user = { userId, username, ... };
      next();
   } catch (error) {
       res.status(401).json({msg:"用户验证失败"})
   }
};

三. 应用场景

  1. JWT & localStorage
  2. JWT & Cookie

3.1 存储在 localStorage

  1. 服务端:将 token 返回给客户端
    const login = async (req, res) => {
       // ...登录成功后
       // ...生成完 token
       const token = "your_token"
       
       // 将 token 返回给客户端
       res.status(StatusCodes.OK).json({
           msg: '登录成功',
           token,
        });
    };
    
  2. 客户端:将 token 存储到 localStorage,并在后续请求中将 token 发送给服务端。为了方便管理,这里简单封装了下 aixos:
    import toast from 'react-hot-toast';
    
    // 创建 axios 实例,把本地的 token 放在 header 中:
    const axiosInstance = axios.create({
         baseURL: '/api/v1',
         timeout: 3000,
         headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }, // 每个请求都自动携带 token
     });
     
     // 是否显示成功的提示或者失败的提示
     const defaultConfig = {
         showError: true,
         showSuccess: false
     }
     const request = (url: string, config= {}) => {
         const _config = {
             ...defaultConfig,
             ...config
         }
         const { data, params } = _config
         const method = _config.method || 'get'
    
         return axiosInstance.request({
             url,
             method,
             data: data || {},
             params: params || {},
         }).then((res) => {
             const data = res.data;
             _config.success && _config.success(data);
             if (_config.showSuccess) toast.success(data.msg || '请求成功');
             return data as TResData<T>
         }).catch((err) => {
             if (err.response.status >= 500) {
                 toast.error('服务器发生错误,请稍后再试')
             }
             // 如果用户校验失败,重新返回登录页
             if (err.response.status === 401) {
                 toast.error('用户凭证出现问题,请重新登录')
                 location.href = '/login'  
             }
             // 其他错误
             let data = err.response.data
             _config.error && _config.error(data)
             if (_config.showError) toast.error(data.msg || '未知错误')
             return data
         })
     }
    

现在基于这个封装好的 request,写一下示例。

(1) 登录时存储 token

request('/login', {
      method: 'POST',
      data: {
         username,
         password,
      },
      showSuccess: true,
      success: (data) => {
         localStorage.setItem('token', data.token); // 登录成功后将 token 存储
         location.href = '/home'; // 跳转到主页 
      },
   });

结果如下:

Node.js中使用JWT、localStorage、Cookie校验用户信息 1

// 用户验证中间件
const authToken = async (req, res, next) => {
   const token = req.cookie.token;  
   // 等同于:req.headers.cookie.split('=')[1]
   // 如果上面的 signed 为 true, 则  const token = req.signedCookies.token;

   if (!token) {
      res.status(401).json({msg:"No token provided"})
   }

   try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET); // 传入 token 和秘钥
      // 拿到解出来的 { userId, username }
      // 将信息挂载 req.user 中供后续接口使用
      req.user = { userId, username, ... };
      next();
   } catch (error) {
       res.status(401).json({msg:"用户验证失败"})
   }
};

使用中间件:

app.use('/api/v1/groups', authToken, groupsRoute);
  • 服务端:对于退出登录,还需要清除 Cookie 的 token
    const logout = async (req, res) => {
       res.clearCookie('token')
       res.status(StatusCodes.OK).json({
          msg:'成功退出'
       })
    }
  • 结语

    综上所述,Node.js 中使用 JWT、localStorage 和 Cookie 校验用户信息是一种可行的方法。服务端通过校验 JWT 的合法性和有效性,将用户信息放入请求中;客户端通过将 JWT 存储在 localStorage 或 Cookie 中,实现用户信息的传递和校验。这种方法灵活且安全,可应用于各类 Node.js 应用中。

    标签:cookie