node.js学习(session和token)

大佬们👦好,前后端身份是如何认证的?为什么你登录了一次之后再访问,会显示你在登录? 可能这就是sessiontoken的魅力。请慢慢来了解;希望多多支持!🕢 🔥

前后端的身份验证

身份认证

通过一定的手段,完成对用户身份的确认。

不同开发模式下的身份认证

  1. 服务端渲染推荐 Session 认证机制
  2. 前后端分离推荐使用 JWT 认证机制
Session 认证机制
  1. http 协议的无状态性

    http 协议,指的是客户端的每次 http 请求都是独立的,连续多个请求之间没有直接关系,服务器不会主动保留每次 http 请求的状态。

  2. Cookie

    Cookie 是存储在用户浏览器中的一段不超过 4kb 的字符串,它有一个名称、一个值和其他用于控制 Cookie 有效期、安全期、使用范围的可选属性组成。
    在这里插入图片描述

不同域名下的 Cookie 各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的 Cookie 一同发送给服务器

特性:

  1. 自动发送
  2. 域名独立
  3. 过期时限
  4. 4kb 限制

Cookie 不具备安全性,可以伪造,因此,不建议服务器将重要的隐私数据,通过 Cookie 的形式发送

在 express 使用 Session 认证
  1. 安装 express-session 中间件
npm i express-session
  1. 配置 express-session 中间件
// 导入
const session = require("express-session");
// 配置中间件
app.use(
  session({
    secret: "keyboard cat", //secret 属性的值可以是任意字符串
    resave: false, // 固定写法
    saveUninitialized: true, // 固定写法
  })
);
  1. 使用 session
const express = require("express");
const app = express();
// 导入
const session = require("express-session");
const port = 3000;
// 配置
app.use(
  session({
    secret: "itheima",
    resave: false,
    saveUninitialized: true,
  })
);
// api接口
app.post("/api/login", function (req, res) {
  // 判断用户登录信息是否正确
  if (req.body.username !== "admin" || req.body.password !== "00000") {
    // 失败
    return res.send({ status: 1, msg: "登录失败" });
  }
  // 成功
  req.session.user = req.body;
  req.session.isLogin = true;
});
// 从session中取数据
// 获取username的接口
app.get("/api/username", (req, res) => {
  if (!req.session.isLogin) {
    // 失败
    return res.send({ status: 1, msg: "fail" });
  }
  //   成功
  res.send({
    status: 1,
    msg: "success",
    username: req.session.user.username,
  });
});

app.listen(port, () => {
  console.log(`server port running at ${port}`);
});

JWT 认证机制

Session 需要配合 Cookie 才能实现,由于 cookie 不支持跨域,当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域 Session 认证。

注意:

  • 当前段请求后端接口不存在跨域问题的时候,推荐使用 Session 身份认证机制。
  • 当前端需要跨域请求后端接口时候,推荐使用 JWT 人生机制。

组成部分

Header(头部)、Payload(有效负荷)、Signature(签名)

格式

Header.Payload.Signature;

Payload 部分才是真正的用户信息,它是用户信息经过加密之后生成的字符串

Header 和 Signature 是安全性相关的部分,知识为了保障 Token 的安全性

使用方式

客户端收到服务器返回的 JWT 之后,通常会将它存储在 localStoragesessionStorage 中;

此后,客户端每次与服务器通信,都要带上这个 JWT 的字符串。从而进行身份验证,推荐的做法是把 JWT 方在 http 请求头的 Authorization 字段中

格式

Authorization:Bearer <token>
安装 JWT 相关的包

npm i jsonwebtoken express-jwt

jsonwebtoken: 用于生成 JWT 字符串
express-jwt:用于将 JWT 字符串解析还原成 JSON 对象

// 导入
const jwt = require("jsonwebtoken");
const expressJWT = require("express-jwt");
定义 secret 秘钥
  • 为了保证 JWT 字符串的安全性,防止 JWT 字符串在网络传输过程中被别人破解,需要定义一个用于加密和解密的 secret 秘钥
    • 当生成 JWT 字符串时,需要使用 secret 对用户信息进行加密。
    • 当把字符串解析还原成 JSON 对象时,需要用 secret 秘钥解密
// 定义secret秘钥
const secretKey = "itheima No1";
在登录后生成 JWT 字符串

调用 jsonwebtoken 包提供的 sign()方法,将用户的信息加密成 JWT 字符串,响应给客户端。

参数:

  1. 用户信息对象
  2. 加密秘钥
  3. 配置对象
const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, {
  expiresIn: "30s",
});

接口

app.post("/api/login", (req, res) => {
  res.send({
    status: 200,
    message: "success",
    token: tokenStr,
  });
});
将 JWT 字符串还原为 JSON 对象

客户端每次在访问那些有权限接口时,都要主动通过请求头中的 authorization 字段,将 token 字符串发送到服务器进行身份验证。

此时,服务器可以通过 express-jwt 这个中间件,自动将客户端发送过来的 token 解析还原成 JSON 对象

// 使用app.use()注册中间件
// expressJWT({secret:secretKey}) 用来解析token中间件
// .unless({path:[/^\/api\//]})  用来指定哪些接口不需要访问权限
app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }));
使用 token
const express = require("express");
const app = express();
const port = 3000;

// 导入
// 加密
const jwt = require("jsonwebtoken");
// 解密
// ****** express-jwt 要安装7.0版本以下的 不然会报错 建议 安装6.1.1
const expressJWT = require("express-jwt");

// 定义secret秘钥
const secretKey = "itheima No1";

// 注册express-jwt中间件
app.use(
  // algorithms: ["HS256"] 防止express-jwt版本过高报错
  expressJWT({ secret: secretKey, algorithms: ["HS256"] }).unless({
    path: [/^\/api\//],
  })
);

// 解析 post 表单数据的中间件
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));

// 允许跨域
const cors = require("cors");
app.use(cors());

// 登录接口
app.post("/api/login", function (req, res) {
  // 将 req.body 请求体中的数据,转存为 userinfo 常量
  const userinfo = req.body;
  // 登录失败
  if (userinfo.username !== "admin" || userinfo.password !== "000000") {
    return res.send({
      status: 400,
      message: "登录失败!",
    });
  }
  // 登录成功
  // TODO_03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
  // 参数1:用户的信息对象
  // 参数2:加密的秘钥
  // 参数3:配置对象,可以配置当前 token 的有效期
  // 记住:千万不要把密码加密到 token 字符中
  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, {
    expiresIn: "100s",
  });
  res.send({
    status: 200,
    message: "登录成功!",
    token: tokenStr, // 要发送给客户端的 token 字符串
  });
});

app.post("/admin/getinfo", function (req, res) {
  // token会直接挂载到req的user属性上
  console.log(req.user);
  res.send({
    status: 200,
    message: "获取成功",
    data: req.user,
  });
});

// 捕获失败的中间件
app.use((err, req, res, next) => {
  // 这次错误是由 token 解析失败导致的
  if (err.name === "UnauthorizedError") {
    return res.send({
      status: 401,
      message: "无效的token",
    });
  }
  res.send({
    status: 500,
    message: "未知的错误",
  });
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

在这里插入图片描述
在这里插入图片描述

捕获解析 jwt 失败后产生的错误

如果客户端发过来的 token 自飞船过期或不合法,会产生一个解析错误,可以通过express的错误中间件,捕获错误并处理

app.use((err, req, res, next) => {
  if (err.name == "UnauthorizedError") {
    return res.send({
      status: 401,
      message: "无效的token",
    });
  }
  // 其他原因
  res.send({ status: 500, message: "未知错误" });
});

🔥🔥🔥但行前路,不负韶华!努力学习👍 🔥🔥

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

章鱼哥vlog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值