文章目录加载中
身份认证-Session机制
# 认识 Session
Session 机制准确来说,也是通过 K-V 数据格式来保存状态。其中:
- Key:也称 SessionID,保存在客户端浏览器。
- Value:也称“Session”,保存在服务端。
可以看到,客户端只需要存储 SessionID。具体映射的数据结构放在了服务端,因此跳出了仅仅浏览器 cookie 只可以存储 string 类型的限制。
而客户端存储 SessionID,还是需要借助 cookie 来实现。
# 整体流程
假设/login
接口登陆成功后,服务器可以生成 sessionId 和 session。其中,session 中保存了过期时间,一些冗余信息等。代码如下:
router.get("/login", async (ctx, next) => {
const { user, pwd } = querystring.parse(ctx.request.search.slice(1));
// mock数据,模拟一下登陆过程
if (user === "test" && pwd === "123456") {
// 生成客户端存储的sessinId
const sessionId = crypto
.createHash("md5")
.update(user + pwd)
.digest("hex");
// 生成服务端存储的session
const session = {
expire: Date.now() + 1000 * 60 * 60 * 24, // 过期时间
info: {
// 保存的信息
name: user
}
};
sessions.set(sessionId, session);
ctx.cookies.set("sessionId", sessionId);
ctx.response.body = "登陆成功";
} else {
ctx.response.body = "登陆失败";
ctx.response.status = 401;
}
});
然后客户端在 cookies 中携带 sessionId,访问/userInfo
接口,获得用户信息。服务端检查 sessionId 合法性,以及是否过期。代码如下:
router.get("/userInfo", async (ctx, next) => {
const sessionId = ctx.cookies.get("sessionId");
const session = sessions.get(sessionId);
// 如果sessionId不存在
if (!session) {
ctx.response.body = "无法识别身份";
ctx.response.status = 401;
return;
}
// session过期
if (session.expire <= Date.now()) {
ctx.response.body = "session过期,请重新登陆";
ctx.response.status = 401;
return;
}
ctx.response.body = session.info;
});
打开 chrome dev tools,我们可以看到,http 请求自动携带了 cookie 中的
sessionId。并且通过后端检验,拿到了用户信息。
# 总结:比较 cookie 与 session
session 传输数据少,数据结构灵活:相较于 cookie 来说,session 存储在服务端,客户端仅保留换取 session 的用户凭证。因此传输数据量小,速度快。
session 更安全:检验、生成、验证都是在服务端按照指定规则完成,而 cookie 可能被客户端通过 js 代码篡改。
session 的不足:服务器是有状态的。多台后端服务器无法共享 session。解决方法是,专门准备一台 session 服务器,关于 session 的所有操作都交给它来调用。而服务器之间的调用,可以走内网 ip,走 RPC 调用(不走 http)。
本文来自心谭博客:xin-tan.com,经常更新web和算法的文章笔记,前往github查看目录归纳:github.com/dongyuanxin/blog