node中使用jsonwebtoken实现身份认证

在现代web应用中,用户身份认证是非常重要且必不可少的一环。而使用Node.jsExpress框架,可以方便地实现用户身份认证。而在这个过程中,jsonwebtoken这个基于JWT协议的模块可以帮助我们实现安全且可靠的身份认证机制,可以让我们轻松地生成、解析和验证JWT。本文主要介绍如何在Node.jsExpress框架中使用jsonwebtoken模块来实现用户身份认证。

一、什么是jwt

jwt介绍https://restfulapi.cn/jwt

JWTJSON Web Token)是一种基于JSON的开放标准,用于在网络上以安全方式传输声明JWT通常用于身份验证和授权。它是一种可自包含的身份认证机制,由三部分组成头部、载荷和签名JWT的头部和载荷都是使用Base64编码后的JSON字符串,签名是由头部和载荷使用密钥进行哈希计算得到的字符串。JWT可以在客户端和服务器之间传输,并且可以在传输过程中防止数据被篡改。由于它是无状态的,因此可以简化Web应用程序的开发和维护。
在这里插入图片描述

二、jsonwebtoken基本使用

jsonwebtoken是一个Node.js库,用于创建、解码和验证JWT令牌(JSON Web Tokens)。在Web应用中,这些令牌通常用于身份验证和授权

以下是如何在Node.js应用中使用jsonwebtoken基本步骤

1. 安装jsonwebtoken

首先,你需要使用npm或yarn将jsonwebtoken包添加到你的项目中:

npm install jsonwebtoken --save

或者

yarn add jsonwebtoken

2. 导入使用

然后,在你的代码中导入jsonwebtoken:

const jwt = require('jsonwebtoken');

3. 创建token

创建一个令牌:

let token = jwt.sign({
    
     foo: 'bar' }, 'shhhhh');

在上面的代码中,我们使用jwt.sign方法创建了一个新的令牌。
这个方法需要两个参数

  • 一个包含你的payload的对象(这个对象中的数据会被编码到生成的令牌中)比如:userInfo
  • 用来签名令牌的秘密字符串

4. 验证token

验证一个令牌:

jwt.verify(token, 'shhhhh', (err, decoded) => {
    
    
  if (err) {
    
    
    // 处理错误
  } else {
    
    
    // 使用解码后的令牌数据
  }
});

使用jwt.verify方法可以解码并验证一个令牌。

该方法需要三个参数

  • 解码的令牌
  • 用于签名的相同的秘密字符串
  • 操作完成时被调用的回调函数

注意

  • 所有的令牌都应该只通过HTTPS发送,以防止被拦截。

  • 秘密字符串应该在你的应用中保持私密,不能让其他人知道。

  • 任何存储在令牌中的信息都可以被任何拥有秘密的人解码。因此,你永远不应该在令牌中存储敏感信息(如密码或银行账户信息)

三、在express中应用示例

在实际项目中,我们可以使用jsonwebtoken模块来实现身份认证。jsonwebtoken是基于JSON Web Tokens(JWT)协议的实现模块,可以用于生成、解析和验证JWTJWT是一种基于JSON的开放标准(RFC 7519),用于在网络上安全地传输声明。

以下是一个使用expressjsonwebtoken实现身份认证的示例:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// 定义一个中间件函数,用于身份认证
function verifyToken(req, res, next) {
    
    
  // 从请求头中获取token
  const token = req.headers['authorization'];
  if (!token) {
    
    
    return res.status(401).send({
    
    
      auth: false,
      message: 'No token provided.'
    });
  }

  // 验证token是否有效
  jwt.verify(token, process.env.SECRET_KEY, (err, decoded) => {
    
    
    if (err) {
    
    
      return res.status(500).send({
    
    
        auth: false,
        message: 'Failed to authenticate token.'
      });
    }

    // 将解码的用户信息存储到请求对象中
    req.userId = decoded.id;
    next();
  });
}

// 定义一个路由,需要身份认证
app.get('/api/protected', verifyToken, (req, res, next) => {
    
    
  // 返回受保护的数据
  res.status(200).send({
    
    
    message: 'Access granted.'
  });
});

// 定义一个路由,用于登录,返回token
app.post('/api/login', (req, res, next) => {
    
    
  // 从数据库中获取用户信息
  const user = {
    
     id: 123 };

  // 生成token
  const token = jwt.sign({
    
     id: user.id }, process.env.SECRET_KEY, {
    
    
    expiresIn: 60 * 60 // token有效期为1小时
  });

  // 返回token
  res.status(200).send({
    
    
    auth: true,
    token: token
  });
});

// 启动服务器,监听端口
app.listen(3000, () => {
    
    
  console.log('Server started on port 3000');
});

在上述示例中,我们定义了一个中间件函数verifyToken用于身份认证。该函数从请求头中获取token,并通过jsonwebtoken的verify方法验证token是否有效。如果验证通过,则将用户信息存储到请求对象中,以便后续路由函数使用。

我们还定义了两个路由函数,/api/protected/api/login/api/protected需要身份认证才能访问,而/api/login用于登录,并返回生成的token

在实际项目中,我们应该将SECRET_KEY等敏感信息放在环境变量中,以提高安全性。此外,我们还可以使用jsonwebtoken提供的其他功能,如验证token的签名算法、payloadheader等信息。

四、jwt逻辑抽离

在上面的示例中我们用jwt实现了身份认证,但是这只是在一个接口中认证,如果接口多了呢,每次都要将这个认证的中间件加上吗?这样先不说开发实现的累不累,冗余不,单从维护层面来讲,也是很不合理。所以我们应该将认证的逻辑抽离出来,以便于接口调用和维护。具体步骤如下:

1. 新建jwt.js文件

这个文件中就封装三个函数

  • token的生成
  • token的认证
  • 排除哪些接口不需要认证就可以访问,比如/login,
// jwt.js
const jwt = require("jsonwebtoken");
const {
    
     promisify } = require("util");
const {
    
     uuid } = require("../config/config.default");
const tojwt = promisify(jwt.sign);
const verfiy = promisify(jwt.verify);

// 生成token
module.exports.createToken = async (userinfo) => {
    
    
  var token = await tojwt({
    
     userinfo }, uuid, {
    
    
    expiresIn: 60 * 60 * 24,
  });
  return token;
};

// jwt认证的中间件
const jwtAuthMiddleware = async (req, res, next) => {
    
    
  var token = req.headers.authorization;
  token = token ? token.split("Bearer ")[1] : null;
  if (!token) {
    
    
    return res.status(402).json({
    
     error: "请传入token" });
  }
  if (token) {
    
    
    try {
    
    
      let userinfo = await verfiy(token, uuid);
      req.user = userinfo;
      next();
    } catch (error) {
    
    
      res.status("402").json({
    
     error: "无效的token" });
    }
  } else {
    
    
    next();
  }
};

// 承认的url排除列表
const jwtAuthExcluedList = ['/api/login', '/api/register'];
// 检查排除列表的中间件
module.exports.jwtAuthExclued = (req, res, next) => {
    
    
  // 检查请求 URL 是否在排除 jwtAuth 的列表里面
  if (jwtAuthExcluedList.includes(req.path)){
    
    
    next(); // 在列表里,跳过后续中间件
  } else {
    
     
    jwtAuthMiddleware(req, res, next); // 不在列表里,就调用jwt中间件进行身份认证
  }
};

这样封装以后,我们只需要在访问路由之前,添加使用jwtAuthExclued 的中间件就可以实现对接口的token认证,在login接口中调用createToken生成token可以了。

2. 在登录接口中生成token

比如:

  • loginController
// login
// 用户登录
exports.login = async (req, res) => {
    
    
  // 客户端数据验证
  // 链接数据库查询
  var dbBack = await User.findOne(req.body)
  if (!dbBack) {
    
    
    return res.status(402).json({
    
     error: "邮箱或者密码不正确" })
  }

  dbBack = dbBack.toJSON()
  dbBack.token = await createToken(dbBack)
  res.status(200).json(dbBack)
}

3. 添加全局认证中间件

  • app.js
const express = require("express");
const app = express();
const {
    
     jwtAuthExclued } = require("./util/jwt");
const router = require("./router");


// 添加排除jwt中间件
app.use(jwtAuthExclued); 
// 添加路由中间件
app.use('/api', router);

五、jwt和session对比

下面是JWTSession的对比表格:

对比因素 JWT Session
存储 存储在客户端,不需要服务器保持会话状态。 存储在服务器,需要服务器维护会话信息。
安全性 加密较严密,但如果token被窃取,攻击者可以任意使用。 如果sessionID被窃取,攻击者可以冒充用户登陆。
性能 在每次请求时需要验证和解码token,性能较差。 只需查找sessionID就能获取会话信息,性能较好。
扩展性 在多服务器或者跨域环境中更易扩展。 在多服务器环境中需要同步session,扩展性较差。
数据大小 JWT的大小比sessionID大,因此需要更多的带宽。 sessionID大小稳定,对带宽需求较小。
到期时间 可以为每个token设置不同的过期时间。 所有session的过期时间通常相同。
客户端存储位置 可以存储在Cookie, LocalStorage, SessionStorage中 存储在Cookie中。
跨域问题 无跨域问题,且对于移动应用而言友好。 跨域问题复杂,需要服务器支持CORS。
状态 无状态,服务器不需要保存用户信息。 有状态,服务器需要保存用户信息。
使用场景 用于认证和信息交换,尤其适合单页应用(SPA)和前后端分离的项目 主要用于记录用户状态,适配传统的后端渲染的Web服务

总体上来说,JWT适用于前后端分离的API服务,它可以简化服务端的存储需求,并提供更好的跨平台兼容性和可扩展性,同时也能提供安全可靠的身份认证机制。而Session适用于服务器渲染的Web应用,它可以提供更高的安全性和可调用性,同时也能减轻客户端的流量负担。不同的场景需要选择最适合的身份认证方案,根据实际需求进行选择。

六、总结

在本文中,我们探讨了如何在Node.jsExpress框架中使用jsonwebtoken来实现身份认证。我们首先介绍了JWT协议和jsonwebtoken模块的基础知识,然后展示了如何在Express中使用jsonwebtoken来生成、解析和验证JWT。通过在实际项目中的举例,我们演示了如何将jsonwebtoken与路由中间件结合使用,实现基于token的用户身份认证机制。使用jsonwebtoken可以为我们的web应用提供更安全和可靠的用户身份认证方案,同时jwt的优点也是很明显的:无需在服务端保存session信息,具有可扩展性和跨平台兼容性等特点。通过本文的介绍,相信读者已经能够掌握jsonwebtoken的基本使用方法和原理,能够在实际项目中使用jsonwebtoken实现安全可靠的身份认证机制。

猜你喜欢

转载自blog.csdn.net/jieyucx/article/details/131951952
今日推荐