一份登录设计方案

在做过的项目里,我总结了下,在说关于登录的设计之前我们需要了解下 Session 和 Cookie。

Session 

因为 HTTP 协议是无状态的,我们无法知道客户端在访问服务器时候的状态是什么样的,因此出现了 Session 和 Cookie,Session 是存放在服务器上的,通过 Session 我们可以知道客户端的会话状态,Session 对应 Java 中的 HttpSession,在 getSession() 时会创建一个 session,同时产生与之关联的 sessionId。Session 会随着 HTTP 响应,下次发出请求时候会在 HTTP 头里带上 sessionId,服务器根据 sessionId 来得到与之对应的id得到与之对应的 session。由于 session 存放于服务器端,也会出现问题:

  • 在集群模式下,需要对 Session 做一个转移同步;
  • Session 会消耗服务器端的存储。

Cookie

HTTP 协议本身是无状态的。什么是无状态呢?即服务器无法判断用户身份。Cookie 实际上是一小段的文本信息(key-value格式)。客户端向服务器发起请求,如果服务器需要记录该用户状态,就使用 response 向客户端浏览器颁发一个 Cookie。客户端浏览器会把  Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。

在了解完 Session 和 Cookie 后,我们再来看一下 JWT 的概念。

登录设计

在设计方案中,有两种,一种是和 Session 有关,另一种是和 Cookie 有关,下来我们依次介绍:

1) Session 设计

我们用 Session 作为登录标志的话,会存在内存消耗和集群一致性问题,为了解决这个问题,我们可以把 sessionId 存放在 Redis 中作为 token,流程图如下:

图片

浏览器的请求过来访问服务器,先会走网关,在网关里我们做了过滤器来过滤请求,看请求中是否携带了 token。

  • 如果携带了 token 再去 Redis 中查询是否存在,存在的话则 chain.filter 放行;
  • 如果 token 不存在或者 Redis 中不存在表示会话过时,需要重新登录。这时候前端会跳转到登录界面,这次的请求就会访问 user 服务。

验证用户名和密码正确之后,通过 HttpSession.getSession(),获取到 session,再将 业务名+sessionId 作为 key,用户信息作为 value 存放到 Redis 中,sessionId 作为 token 返回给前端。前端下次访问的时候会带上 sessionId,这样我们就确定了用户是否登录。

这样的设计思路的好处是:session 做了同步转移,又减少了服务器的压力,也减少了 user 服务的访问量,不必每次都来查看用户名密码是否正确。缺点是虽然将 session 存到了 Redis 中但是无疑增加了系统的复杂性,Session 依赖于 Cookie,但是移动端经常没有 Cookie,并且如果浏览器仅启用了 Cookie,还需要在 URL 后面添加 sessionId。

在了解基于 Cookie 的登录认证之前,我们需要先了解一下 JWT。

JWT

token 的一种具体实现方式,其全称是 JSON Web Token,官网地址:jwt.io/ ,整个格式是 JSON 格式。

JWT由三部分组成:

  • 标头:头部包括令牌的类型(例如 JWT) 使用的哈希算法(例如 RSA)
  • 负载:存放有效信息的地方,比如签发者、过期时间、也可以自定义(例如用户的基本信息)
  • 签名:此部分防止 JWT 被篡改,这个部分用 base64url 将前两部分进行编码。

非对称加密算法

加密和解密使用不同的秘钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。私钥加密的信息,只有公钥才能解密。常见的非对称加密算法例如 RSA、ECC。

2) cookie 设计

这是我做之前项目的时候使用的登录授权,Cookie 的安全性一直是一个问题,虽然将 HttpOnly 设置为 true 可以防止 js 脚本窃取信息,但是为了安全起见我们还是需要对 token 进行加密,保证用户信息的安全,设计图如下:

图片

除授权服务外,每个服务配置文件里都存放这个公钥,授权服务中存放着对应的私钥,请求来的时候走网关,网关中的 filter 会对 token 使用公钥进行解密。

  • 解密成功,则对 Cookie 里的 token 刷新过期时间,返回 200,跳转界面;
  • 解密失败则返回,到登录界面登录之后转到授权服务。

来到授权服务里,先验证完用户名和密码。之后使用 JWT 工具,使用私钥对用户信息加密,生成 JwtToken。最后再将 token 写入 Cookie,设置过期时间,并设置 httpOnly 设置为 true,防止 js 脚本窃取信息。

图片

转自:我再也不喝酒啦,

链接:juejin.cn/post/7060376989059776549

扫码领红包

微信赞赏支付宝扫码领红包

发表回复

后才能评论