木灵鱼儿
阅读:2418
koa框架20 cookie、session
cookie
cookie用于判断用户是谁,一般都是使用签名算法进行加密。加上cookie本身大小有限制,总大小才32k,头信息也才32k,所有不能太大,而且不能太多,最多20条,容量这样一算的话,单条才4k。
koa创建cookie直接通过ctx对象:
ctx.cookies.set(key,value);
读取:
ctx.cookies.get(key);
签名
server.keys = ["aaaa", "bbbb", "cccc"];
router.get("/", async ctx => {
ctx.cookies.set("name", "mulingyuer", { signed: true });
})
这样会在服务种一个key为name.sig
,值已经被加密的cookie。
如果你要获取这个cookie,由于已经加密了,所有要这样写:
router.get("/", async ctx => {
console.log(ctx.cookies.get("name", { signed: true }))
})
此时koa会将加密后的值获取并解析成原来的内容。
我们通过给server设置keys数组,里面存放一些密匙,然后再获取或者设置cookie是增加一个配置,就能做到签名,但是如何生成一堆随机的密匙呢?
生成密匙
生成密匙我们需要安装一个插件 uuid
npm i uuid
新版的uuid引入方法和旧版不同,官方示例:
const { v4: uuidv4 } = require('uuid');
uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'
也就是说通过解构的方式我们调用V4版本,uuid有好几个版本,v1,v2,v5,v4,我们使用v4就行了。
然后它本身就是一个函数,uuid会生成全局唯一id,理论上是不会出现重复的。
我们利用这个方法可以创建唯一的id,创建的话,也不用每次启动服务都创建,我们可以封装成一个文件,每次调用的时候生成一次文件并保存,下一次就直接使用文件。
const {
v4: uuid
} = require("uuid");
const fs = require("fs");
const path = require("path");
let arr = [];
const n = 1024;
for (let i = 0; i < n; i++) {
let str = "";
for (let j = 0; j < 32; j++) {
str += uuid().replace(/\-/g, "");
}
arr.push(str);
};
//保存
fs.writeFileSync(path.resolve(__dirname, ".keys"), JSON.stringify(arr));
console.log("key生成成功");
我们创建1024个key,每个key由32个uuid组成,并且我们通过repalce将uuid的短横线去掉了。
然后我们保存到一个数组里面。
接着使用原生模块fs将文件保存在本地,writeFileSync是一个同步操作,注意,他是一个同步操作,不是一个异步的。
我们再通过path来创建一个相对地址拼接,其中__dirname
的关键词他的意思是相对于当前运行的js文件路径,此时我要存到当前路径,我们只需要加个文件名就行了,最后生成了fs需要的第一个参数。
第二个参数就将数组json化传入即可,然后我们可以得到一个1024的文件。
我们给文件名取名.keys
,用点的话,在linux里面,默认是隐藏的,也不能说很安全,但是也是一个方式吧。
使用keys
keys创建好后,我们可以在server.js中使用,先通过fs模块读取这个文件,首先要说明一点,我们肯定是需要在keys完全读取后才能运行服务,所有不需要使用异步读取文件。
const Koa = require("koa");
const static = require("koa-static");
const body = require("koa-better-body");
const convert = require("koa-convert");
const Router = require("koa-router");
const path = require("path");
const fs = require("promise-fs");
const server = new Koa();
try {
server.keys = JSON.parse(fs.readFileSync(path.resolve(__dirname, "keys/.keys")).toString());
} catch (e) {
console.log("keys读取失败,请查看是否创建");
return;
}
server.use(convert(body({
uploadDir: path.resolve(__dirname, "upload")
})))
const router = new Router();
// server.keys = ["aaaa", "bbbb", "cccc"];
router.get("/", async ctx => {
console.log(ctx.cookies.get("name", {
signed: true
}))
})
server.use(router.routes());
server.use(static("./static", {
// maxage: 30 * 24 * 60 * 60 * 1000, //30天缓存周期
index: "index.html" //默认文件
}))
server.listen(8080);
由于我们需要先加载keys,所以,监听端口要放在最后,然后我们还要给fs判断,如果报错了,说明key文件不存在或者其他,我们要停止运行这个服务。
cookie的其他设置
- maxAge: 有效期(ms)
- signed: true/false 签名
- path: cookie路径,能向下访问,不能向上,一般没要求给根路径
/
,不然默认当前路径 - domain: 域名,限制域名访问,一般的给根域名,省事
- secure:true/false https访问
- httpOnly: 只能通过http访问,只有服务器能访问,前台js不能访问
这些都是ctx.cookies.set(key,value,{设置})的设置参数。
session
我们需要安装koa-session插件
npm i koa-session
然后我们使用
const Koa = require("koa");
const static = require("koa-static");
const Router = require("koa-router");
const path = require("path");
const fs = require("promise-fs");
const session = require("koa-session");
const server = new Koa();
try {
server.keys = JSON.parse(fs.readFileSync(path.resolve(__dirname, "keys/.keys")).toString());
} catch (e) {
console.log("keys读取失败,请查看是否创建");
return;
}
server.use(session({
maxAge: 20 * 60 * 1000,
renew: true
}, server));
server.use(router.routes());
server.use(static("./static", {
// maxage: 30 * 24 * 60 * 60 * 1000, //30天缓存周期
index: "index.html" //默认文件
}));
server.listen(8080);
也是通过中间件的方式激活,但是这在之前,session也要和cookie一样使用keys加密,所有在激活之前,我们还需要调用keys文件并赋值给server.keys属性。
调用的时候,第一个参数为配置,第二个为server对象,因为他要对server对象进行操作,server对象就是new Koa()的那个对象。
然后就是设置sessio了
给用户设置session
上面配置完毕后,后端直接给每个浏览器配置一个session,我们在后端直接操作session的内容,不需要考虑怎么配置,怎么读取,怎么设置。
直接同ctx对象的session属性,然后他本身可以理解为一个json对象,所以也是键值对的方式存储。
router.get("/", async ctx => {
if (ctx.session["view"]) {
ctx.session["view"]++;
} else {
ctx.session["view"] = 1;
}
ctx.body = `第${ctx.session["view"]}次访问`;
});
我们就直接设置对应的session属性就行了。
当用户超过20分钟没有进行请求的时候,session就会到期,再次请求时,属性就会清除,一切又从0开始。
session的一些配置
- key 自定义cookie中存储session id的key名,默认是koa:sess
- maxAge 过期日期,单位ms,默认1天
- autoCommit 自动提交头信息,默认true,不用管
- overwrite 自动覆盖, 默认true,默认就行了
- httpOnly 和那个cookie的一样,默认true,开启后客户端无法通过js修改cookie,但是浏览器本身的设置还是可以的
- signed 签名保护,默认true,必须要,也就是为什么开头要配置server.keys的原因
- rolling 每次访问都要更换session id,默认 false,用的话会影响一些服务器性能,没啥必要开
- rennew 默认false,一般开,session自动延期。
这些配置都是写在session()第一个参数对象里面的。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
centos 安装最新版 node.js
[hide]先用yum 安装一次node先升级yum update 提示下载程序,回复y安装nodeyum install nodejsyum安装的node一般都不是最新的,所以我们还需要升级node的版本npm i n -g全局安装一个n插件n lts表示安装最新的稳定版!一些常用命令n ls查看已安装的node版本n rm 16.0.3删除16.0.3版本更多功能阅读插件文档:n等待安装完毕后,此时其实版本已经安装好了,但是输入node -v还是低版本,是因为centos的用户缓存问题。我们退出登录再登录就会刷新缓存了,此时的node -v输出的就是最新版本exit 退...
node npm yarn 如何同时运行多个指令
node的bash命令其实是有对应的指令字符的,但是,这个指令只能再linux,mac上才有生效,再windows是无效的,所以了解一下就行。命令说明&&顺序执行多条命令,当碰到执行出错的命令后将不执行后面的命令&并行执行多条命令||顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令|管道符windows上进行多命令"scripts": { "dev": "cross-env NODE_ENV=development webpack --env development --progress -...
分享一个利用vuex+session缓存侧边栏数据的方案
前言侧边栏导航大多数情况可能会由后端返回导航内容,第一是方便修改,第二是可以做一些菜单鉴权操作,但是这也会产生一个问题:侧边栏api请求会非常频繁如何避免这个问题,我们就需要使用缓存方案,在web中,缓存有:local,session,cookie,还有一些更复杂的就不说了,用不到。local会永久存储,这样我们刷新页面,数据以缓存优先的话,就会无法及时更新了。passcookie,spa用cookie很少了,而且他有容量限制,直接pass。那么只有session了,session会在页面关闭后自动清理,这样下次重新打开页面数据依旧可以保持最新,并且新建页面,同域名,session也是可...
koa教程2 HttpBearerAuth 传递token
前端发送token到后端,一般有三种方式:链接中携带token,query参数post这种请求body中携带token头信息携带token但是事实上http已经为我们提供了传token的方式,是一个相对来说比较安全的方式,就是HttpBearerAuth 其实他也是一个头信息来着,只是相对来说多了一点操作,在apipost软件中,我们可以直接可视化设置如果是axios,则是需要添加一个头信息:axios({ method: 'get', url: url, responseType: 'blob', headers: { 'Authoriz...

koa教程2 微信openid登录
微信的openid,前端登录时,会发送一个code码到后端,后端接收到这个code,然后配合appid、appsecret参数,像wx发送一个get请求。wx的请求地址:GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code具体查看文档:微信官方文档-服务端可以看到这段get请求有四个参数:属性类型默认值必填说明appidstring 是小程序 appIdsecretstring 是...
koa教程2 权限分级控制
在之前的代码中,我们使用了一个scope属性来表示用户的权限,但是scope是一个数字,他的阅读性是非常差的,当其他人开发的时候,可能并不知道你这个数字是什么意思?所以,我们需要将它转义成文本。为了方便判断,我们在enum.js中增加一个用户等级的对象enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Object.keys(this).find(key => { if (this[key] === val) { return flag = true; } })...
koa教程2 token鉴权
之前我们在token中传入我们的自定义参数,现在我们要做一个token鉴权,很简单,如果他的token合法,就可以访问这个路由,如果不合法,就打回。这个也不能说是真正意义上的鉴权,因为他还没有判断scope值,所以只能说是简单判断。做这个判断我们就可以通过中间件的形式,于是我们在middlewares目录下创建一个auth.js文件auth.js:const parseBearerToken = require("@utils/paresBearerToken"); const jwt = require("jsonwebtoken"); cons...
koa教程2 用户登录
登录类型用户注册之后,自然是用户登录,登录的时候我们需要考虑到登录的方式,往往在正式的项目里面,登录的方式可能会有很多种:账号密码登录手机号登录小程序一键登录那么我们登录的时候就要进行判断,设置一个type的属性,用于在登录时判断用户是什么类型的登录,这个由前端那边设定参数。type:1为账号密码登录,2为手机号登录,3为小程序一键登录作为判断,我们可以写一个查询表(枚举),在项目根目录创建一个lib目录,在里面创建一个enum.js文件。enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Obje...
node 自定义路径别名
用过vue cli的话,对路径中的@应该不陌生,他表示根目录,但是在node的环境里面,我们编写模块并引入时,并没有这种方便的写法。在node环境中,我们可以通过process.cwd()来表示根目录,但是这样的话,每次使用绝对路径引入,路径总是需要写一大堆拼接。const db = require(`${process.cwd()}/config/config`).database;这样略显麻烦,于是我们可以在全局写一个引入插件的方法:global.myRequire = function (path) { return require(`${process.cwd()}/${pa...
koa教程2 密码加密
默认情况下,我们通过User.create({ email, password, nickname });模型传入的数据,是无加密的,也就是说,在数据库中密码是明文显示的,这样肯定是不行,我们需要使用bcrypt插件进行加密yarn add bcryptjs --dev打开models/user.jsuser.js:const bcrypt = require("bcryptjs"); const { sequelize } = require(`${process.cwd()}/core/db`); const { Sequelize, Model, DataTy...
