NodeJS Koa 后端用户会话管理,JWT, Session,长短Token,本文一次性讲明白

前言

前几天,我写了一篇文章,《我设计的一个安全的 web 系统用户密码管理流程》。其中着重点是讲的如何利用非对称加密进行安全的设计,并在讲述了原理之后,又写了 《node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示》 这篇文章,着重讲解了有关 RSA 非对称加密的完整实现。

但是,这些文章里并没有讲到用户登录管理的核心,也就是用户会话管理。这里面有很多概念,对于很多前端开发和很多初级后端开发来说,都是很模糊的。所以,今天,我想通过这一篇文章,把这里面的核心点全部讲明白。

基础概念

我们会听到一些词,大概是 SessionSession IDCookiesToken 等等,现在又有了新词儿,新的解决方案,如 JWT,长短 Token 等等。

我们一个一个来讲。这些词分别有对应的英文意思,但是每个词都有多个含义,并且在不同的环境下,还会有衍生不同的含义。因此,我这边只能从前后端开发的角度去解释这些名词,不能按照字典的含义去解释。

而且,由于网上言论众多,其中谬误的也好,佶屈聱牙的也罢,我都不去管它,我只按照我的理解来讲解,并且,我相信,我的理解是非常深入到位的。

Session

翻译------会话,引申为会话管理。那么,什么是会话呢?

首先,我们要理解一个基础概念------http 服务,是一种无状态服务。怎么理解无状态呢?一句话讲,就是------在默认情况下,后端程序根本不知道前端发过来的请求,谁是谁!

为了解决这个不知道谁是谁的问题,就引申出来解决方案------让后端程序知道,每一个请求,都是谁发出来的,好相应的把对应的资源发回去。

比如,张三请求 profile 接口,返回的内容应该 {name:"张三"},而不能是 {name:"李四"}。

那么,我们就可以理解,张三发出来的一系列的请求,应该归属于一个会话,李四发出来的一系列请求,应该归属于另一个会话。

所以,我们就需要把这一系列的会话,进行管理,这就是会话管理

换句话想,Session,并不是一个单纯的词,而是一个相对很大的概念,为了解决这个问题,不同的语言有不同的解决方案,这些各种不同的解决方案,都可以统称为 Session。

Session ID

理解了上面的 Session 的概念,这个概念就相对比较好理解了。每一个用户,都有一堆的资源,我们不能把这些资源都随时在程序里放着。因此,我们会把这些资源打包存着,然后整出一个 ID 来,方便我们来查询。这样,前端只要给我们这个 ID,我们就可以根据这个ID查找到对应的资源。

这里说的用户资源,是指 用户名,用户昵称,用户角色,过期时间等简短信息,只要方便后端程序快速的分清楚这货是谁,能干些啥事儿即可。不是说,要把所有的用户资源信息,全部存着。如果是那样的话,还要数据库干啥呢对吧。

Token

字面意思,凭证,令牌。是后端下发给前端的一段字符串(可长可短,你要愿意,给数字也不是不行,看你咋设计了。)

前端拿到这个 Token 以后,它每次发起请求时,都需要把这个 Token 给带上,后端根据这个 Token ,就可以去查找对应的资源了。

OK,注意到了吗?上面的 Session ID 是方便我们后端去查找资源的,这个 Token,也是后端去查找对应资源的。

所以------ Token = Session ID ?

答案是不一定。要看你咋设计。

一般而言,我是倾向于设计为 Token,就是 Session ID。当然,也可以不一样,前端给后端 Token,后端先根据 Token 去查找 SessionID,然后根据 ID 再查找对应资源,也是可以的对吧?

但我感觉这样设计有点缺心眼儿。

Cookies

字面意思是一种饼干,我不喜欢吃饼干,所以我不知道它具体是哪一种饼干。

Cookies 是用户浏览器的一种机制,它可以由我们的后端程序去设定。而且,在每次用户发起请求的时候,浏览器都会把 Cookies 自动带上。

换句话讲,如果我们使用 Cookies,可以大幅的减少前端开发的工作量,因为具体是咋实现的,不用管了,浏览器自动实现。

但问题是,现在的前端开发,往往不仅仅是运行在浏览器里面的网页,还有 APP、 小程序或者其他客户端程序,而这些里面,大多是没有 Cookies 的机制的。

因此,为了我们的后端服务可以同时服务多端,我建议就不要管这个玩意儿了。

不是不能用,顺手的时候,也可以兼容。

JWT

JSONWebToken 的缩写。在传统的会话管理里,都涉及一个存储的问题,就是,要把用户资源存着,然后去查询。你可以存在内存里,文件里,数据库里,等等,总之,你要存数据,并且方便查询。

假设,我们存在内存里,而我们的后端服务运行在多台负载均衡的服务器上,那么,当用户的 A 请求访问在甲服务器上,甲服务器在内存里存储了数据,B请求访问在乙服务器上,而乙服务器的内存中并没有用户数据,则会出现读取失败的问题。

怎么解决呢?聪明的你一定想到了解决方案------集中存储,比如单独搞一台 redis 服务器,大家都往这里存。挺好的。

那么假设你的这些服务器不在一个机房呢?也不是不能读是吧,就是慢点儿。

总之,传统的会话管理,有一个问题,就是 IO 问题,也就是存储和读取的问题。

JWT 方案是换了一个思路来解决,其核心原理是,直接将用户的资源信息加密,然后返回给客户端,客户端拿这个加密的长字符串直接作为 Token 来请求,后端程序只要解密字符串,就直接获得了用户的资源信息了。

也就是说, JWT 是用计算复杂度取代了存储复杂度,来解决上面说的问题。

总之,会话管理是一定要消耗资源的,要么是存储复杂度,要么是计算复杂度。


在很多文章和概念里,把 JWT 方案,和 Session 方案并列对比。可以这么比,但是我感觉概念不对。其实在我看来,JWT 方案,只是一种 Session 解决方案而已,两者是上下级的关系,而不是并列的关系。

我这边把传统的通过存储(你别管存哪儿,咋存)解决方案,称之为传统存储方案吧。

和传统存储方案相对比,优缺点如下

特点 JWT 存储
服务器状态 无状态 有状态
跨域支持 天然支持 需CORS配置
实时吊销 默认不支持 支持
传输效率 大点儿,问题不大 小,可忽略

其实总结下来,JWT最大的问题就是,一旦 Token 签发,除了超时失效,否则是没办法把用户登出的。

当然,聪明的你,肯定想到了黑名单机制,把登出的 Token 存下来,然后每次读取验证一下。那么我的问题是,那你为啥不用传统的存储会话管理,要用 JWT ?吃饱撑的?

长短 Token

好,通过上面的这些概念,我们知道,JWT 方案,不方便管理用户,传统存储解决方案,有IO性能问题,那么能不能两种方案结合结合,咱们取长补短!

可以,于是,有了长短 Token 的解决方案。

每次用户登录时,用 JWT 方式,签发一个长的 Token,这个 Token 的过期时间比较短,比如5分钟。5分钟后,它就失效了。

同时,用传统存储方案,签一个短的 Token。这个过期时间可以设置得比较长,比如一个月。

在正常业务时,后端直接读取用户传过来的 JWT 信息,就可以得到用户资源了。当前端发现 token 过期了,就拿 短 token 过来,再请求一个长 token,然后再继续使用。

这样,就解决了存储问题,又可以管理用户登出(直接在存储里删掉用户的短Token 即可)

代价是什么呢?代价是提高了各个前端项目的代码复杂度。你可以说,长短 Token 的解决方案是集合了两种解决方案的长处,也可以理解为,两者的短处也全粘上了。

传输数据变大,还是得存储用户信息,还消耗CPU计算资源等等。

小结

综上所述,我们应该对用户会话管理这块的概念都有了一个清晰的理解了。那么我们在开发项目时应该如何选择呢?

首先,无论是哪种解决方案,你都得会!没有什么方案是一招鲜,吃遍天的。

例如,传统存储方案中的所谓 IO 问题,对于绝大多数项目来说,这就是一个不存在的问题。直接往内存一存,有啥性能瓶颈?拢共就跑在一台服务器上,哪里来的什么速度或者进程共享的问题?在我看来,绝大多数项目,连 redis 都是多余。

再说,JWT 方案,有啥登出管理问题?一个小系统,一天登录拢共就几个人,你设置为有效期1天,我也不认为有多大的安全隐患,如果真遇到了什么大问题,直接把 JWT 的签发加密词一改,所有签发的TOKEN,全部失效。

最后说说长短 TOKEN,如果你团队有足够多的人手,项目也确实有很高的安全性,可以考虑使用。否则,是徒增麻烦。

所以,我推荐你根据你自己的项目选择合适的解决方案,我只说我的观点:

  1. 大多数项目都可以使用 JWT 方案。
  2. 你有切实的要迫使用户登出的项目,比如论坛等等,可以用传统的存储方案。
  3. 你团队实力足够,甲方是安全洁癖,项目也确实有高等级的要求,或者产品或老板想装逼忽悠客户,长短TOKEN你值得拥有!

本来,我是想在这篇文章中,引用一些代码,方便各位看官理解的,没想到,光讲概念就讲了这么多了。没办法,周末抽空,我会把每种方案的 NodeJS + Koa 的实战完整代码给写成文章分享给大家。


最近我在参加 CSDN 的一个创作比赛,各位看官在留言区留言可以给我加分。所以希望各位看官帮帮忙,点评一下哦!

当然,我们程序开发都是很忙滴,没时间点评没关系哈,点个赞,收个藏,也不是不可以哈!耽误不了您的事儿,还能让我继续保持创作热情,小可在这边谢谢各位看官了哈!

相关推荐
代码的余温18 小时前
分布式Session处理的五大主流方案解析
分布式·session
14L1 天前
互联网大厂Java面试:从Spring Cloud到Kafka的技术考察
spring boot·redis·spring cloud·kafka·jwt·oauth2·java面试
Le_ee3 天前
dvwa7——SQL Injection
数据库·sql·网络安全·靶场·token·dvwa
zwjapple6 天前
react-native的token认证流程
react native·状态模式·token
失败尽是常态Z7 天前
基于JWT+Redis的登录流程实现
java·数据库·redis·状态模式·jwt·用户登录
Uranus^12 天前
深入解析Spring Boot与Spring Security整合实现JWT认证
java·spring boot·spring security·认证·jwt
Uranus^13 天前
使用Spring Boot和Spring Security结合JWT实现安全的RESTful API
java·spring boot·spring security·jwt·restful api
白总Server15 天前
Golang基于 Swagger + JWT + RBAC 的认证授权中间件设计
linux·运维·服务器·架构·go·bash·jwt