Node鉴权系列1: Express.js中签名cookie的使用指南(signed cookie)

1,878 阅读1分钟

基本使用

创建cookie

Express直接提供了res.cookie()方法用来给响应头中添加Set-Cookie,达到在浏览器中设置cookie的通,我们只需要:

 function(req, res, next){
    ...
    res.cookie(name, value [, options]);
    ...
}

res.cookie()方法接收三个参数:

  • name: cookie的键,类型为String
  • value:类型为StringObject
  • option: 类型为对象,可使用的属性如下: | 属性名 | 类型 | 说明 | | --- | --- | --- | | domain | String | cookie生效域名 | | expires | Date | cookie的过期时间 | | httpOnly | Boolean | cookie只运行通过Http访问 | | maxAge | Number | cookie多少毫秒后过期 | | path | String | cookie有效路径 | | secure | Boolean | cookie只运行在HTTPS下传输 | | signed | Boolean | 是否使用签名,需要配合cookie-parser使用 |

使用Cookie

在Express中使用Cookie我们需要使用到cookie-parser这款插件

安装cookie-parser

使用npm安装cookie-parser

$ npm install cookie-parser

配置中间件

调用app.use(),配置cookie-parser的中间件

const express = require("express");
const app = express();
const cookieParser = require("cookie-parser");

app.use(cookieParser());

获取cookie

上面的步骤完成后,我们就可以使用req.cookies获取到解析后的cookie,cookie-parser会将其解析为对象的形式。

app.get("/", async function (req, res) {
  res.send(req.cookies)
});

清除cookie

在Express.js中,有两种方式清楚cookie:

res.clearCookie()

第一种是使用Express.js提供的res.clearCookie()方法为。

res.clearCookie(name [, options]);

maxAge: -1

第二种是设置maxAge: -1,让它立马过期:

res.cookie(name, value, { maxAge: -1 });

实战

下面我们使用Express.js来完成三个接口,分别是:

  • 用户是否登录
  • 用户登录
  • 用户登出

引入依赖包

首先我们引入Express的相关依赖,配置中间件,并监听对应的端口。

const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const port = 3099;
const cookieParser = require("cookie-parser");

app.use(bodyParser.json());
app.use(cookieParser());

app.listen(port, () => {
  console.log(`node listening at http://localhost:${port}`);
});

检查是否登录

// 检查用户是否登录
app.get("/", async function (req, res) {
  if (req.cookies.USER_ID) {
    res.send({
      success: true,
      info: `用户【${req.cookies.USER_ID}】已登录`,
      cookie: req.cookies.USER_ID,
    });
  } else {
    res.send({
      success: false,
      info: "用户未登录",
    });
  }
});

用户登录

// 用户登录
app.post("/login", async function (req, res) {
  const { name, pwd } = req.body;
  if (name === "abc" && pwd === 123) { // 这里写死了name和pwd,实际应该从数据库中获取
    res.cookie("USER_ID", "abc", {
      domain: ".node.com", // 设置生效域名
      httpOnly: true, // 只运行Http访问
      maxAge: 1000 * 60 * 60 * 2, // 2个小时过期
    });
    res.send({
      success: true,
      info: "登录成功",
    });
  } else {
    res.send({
      success: false,
      info: "登录失败",
    });
  }
});

用户登出

// 用户登出
app.get("/logout", async function (req, res) {
  res.cookie("USER_ID", "abc", {
    domain: ".node.com",
    httpOnly: true,
    maxAge: -1, // 过期
    httpOnly: true,
  });
  res.send({
    success: true,
    info: "登出成功",
  });
});

修改成签名cookie

当我们登录成功后访问浏览器的cookie,可以看到cookie的value值是明文显示的,这其实十分的不安全,用户可能会篡改cookie。 image.png

设置signed

所以我们需要对cookie进行签名,防止用户的篡改,res.cookie()方法提供了signed配置,如果将其设置为true,则会对其进行签名。下面我们来修改/login这个路由

app.post("/login", async function (req, res) {
  const { name, pwd } = req.body;
  if (name === "abc" && pwd === 123) {
    res.cookie("USER_ID", "abc", {
      domain: ".node.com",
      httpOnly: true,
      maxAge: 1000 * 60 * 60 * 2,
      signed: true, // 设置签名
    });
    res.send({
      success: true,
      info: "登录成功",
    });
  } else {
    res.send({
      success: false,
      info: "登录失败",
    });
  }
});

添加签名的字符串

当你指定了signed:true还没有完成签名的全流程,我们需要在cookieParser(secret)方法中添加签名的字符串才能实现签名。修改cookie-parser中间件的调用:

app.use(cookieParser("your_sercret_str"));

使用signedCookies

在没有设置signed:true前,我们是使用req.cookies来获取cookie的,但是一旦进行了签名,我们需要使用req.signedCookies来获取签名,让我们来修改/路由。

app.get("/", async function (req, res) {
  if (req.signedCookies.USER_ID) {
    res.send({
      success: true,
      info: `用户【${req.signedCookies.USER_ID}】已登录`,
      cookie: req.cookies.USER_ID,
      signedCookies: req.signedCookies.USER_ID,
    });
  } else {
    res.send({
      success: false,
      info: "用户未登录",
    });
  }
});