GX博客

分享个人 Full-Stack JavaScript 项目开发经验

Koa的koa-session中间件使用

koa-session 是 Koa 的简单 session 中间件,需要 Node.js 7.6+ 以对 async/await 支持。它默认使用基于 cookie 存储的 session(session 信息保存在单个 cookie 中),并支持自定义外部储存。下面介绍它的使用步骤:


本地安装 koa-session

yarn add koa-session

将其作为APP中间件

const session = require('koa-session');

app.keys = [process.env.COOKIE_SECRET];

const CONFIG = {
    key: 'koa:sess',
    maxAge: 86400000,
    autoCommit: true,
    overwrite: true,
    httpOnly: true,
    signed: true,
    rolling: false,
    renew: false
};

app.use(session(CONFIG, app));

CONFIG 参数将会传递给 ctx.cookies.get() 和 ctx.cookies.set(),所有配置参数如下:

  • key

    cookie 名称,对应的签名 cookie 在 key 后加 .sig 命名,如 koa:sess.sig。

  • maxAge

    cookie 的有效时间,默认为1天。它允许设置为数字(毫秒),也可以设置为字符串 'session'。

    设置为 'session' 则 cookie 会在浏览会话结束时失效,即关闭浏览器程序时失效。这也意味着,当它被盗时,将永远不会失效。

    如果 Expires 和 Max-Age 均存在,那么 Max-Age 优先级更高。

  • expires

    cookie 的有效时间点,形式为符合 HTTP-date 规范的时间戳。(支持会话恢复功能的浏览器会在重新打开浏览器的时候,将 tab 标签和 cookie 一起恢复。)

  • autoCommit

    自动提交头信息。

  • overwrite

    表示是否覆盖以前设置的同名的 cookie(不管路径或域)。设置为 true,则以前同名的 cookie 将从 Set-Cookie 响应标头中过滤掉。

  • httpOnly

    是否允许客户端 Javascript 读取该 cookie。应该设置为 true 以防范跨站脚本攻击。

  • signed

    是否给 cookie 签名。

  • rolling

    强制在每次响应时重置 cookie 的有效时间(前提是上次 cookie 仍有效)。

  • renew

    在 cookie 即将到期时(到期时间小于 maxAge 的一半)重置它的有效时间。

  • domain

    指定 cookie 可以送达的主机名。假如没有指定,那么默认值为当前文档访问地址中的主机部分(但是不包含子域名)。

  • path

    指定 cookie 的有效路径。请求的资源的路径在为该路径或其子路劲下才发送 cookie。

  • secure

    cookie 只有在请求使用 HTTPS 协议的时候才会被发送到服务器。

如果你使用 Nginx 作为反向代理和 SSL 连接器,想给 cookie 添加 Secure 和 SameSite 标记,则可以在 Nginx 代理层面添加标记,而非在 node.js 应用中设置。最简单的做法是在代理配置中添加 proxy_cookie_path / "/; Secure; SameSite=Strict";。从而将 cookie 的路径规则从 / 简单地替换成 /; Secure; SameSite=Strict。

把session值存储到MySQL

session 内容保存在 cookie 中存在的问题:

  1. koa-session 中间件只会把 session 信息对象的 JSON 字符串经过 base64 编码后保存在 cookie 中。
  2. 浏览器 cookie 会有长度限制。

在 koa-session 配置对象中,可以使用 ContextStore 属性配置 session 的存取和删除方法。它必须为一个类,在每个请求上会执行 new ContextStore(ctx)。

下面是一个将其封装成使用 MySQL 存储的中间件例子:

const session = require("koa-session");

module.exports = (app) => session({
    key: 'auth',
    maxAge: 7200000,
    autoCommit: true,
    overwrite: true,
    httpOnly: true,
    signed: true,
    rolling: false,
    renew: false,
    ContextStore: class MysqlSession {

        constructor(ctx) {
            this.ctx = ctx;
        }

        async get(key, maxAge, {rolling}) {

            // 1、然后根据 key 在数据库查询会话内容(伪造的 key 不会查询到内容)
            // 2、根据 _expire 判断是否有效

            const res = await this.ctx.mysql.raw('CALL get_your_session(?)', key);
            if (res[0][0][0]) {
                const json = JSON.parse(res[0][0][0].session_info);
                if (Date.now() < json._expire) {
                    return json;
                } else {
                    return undefined;
                }
            } else {
                return undefined;
            }
        }

        async set(key, sess, maxAge, {rolling, changed}) {
            await this.ctx.mysql.raw('CALL set_your_session(?,?)', [key, JSON.stringify(sess)]);
        }

        async destroy(key) {

            // 将 ctx.session = null; 以删除 session
            await this.ctx.mysql.raw('CALL destroy_your_session(?)', key);
        }
    }
}, app);

然后在 app.js 中调用该中间件:

const sessionStore = require('./lib/middleware/sessionStore');
app.keys = [process.env.COOKIE_SECRET];
app.use(sessionStore(app));

koa-session 的 session 外键值默认为 Date.now() + '-' + uid.sync(24)。它也可以通过 options.genid 自定义外键,options.genid 为返回自定义键值的函数。

基于安全因素,这个键值应该是唯一、不可猜测、不连续且较长的,默认为其添加时间戳校验可以使其更难以猜测。


了解更多 koa-session 中间件的最新说明,请点击这里
文章关键字:KoaSessionkoa-session

版权声明:

本文为博主原创文章,若需转载,须注明出处,添加原文链接。

https://leeguangxing.cn/blog_post_7.html