什么是鉴权
- 严格来说应该叫用户身份认证。因为 HTTP 协议是无状态的,也就是说用户的上一次访问和下一次访问,对服务器来说都是一次全新的访问,服务器不知道这两次访问之间有什么联系,也不知道访问的用户是谁
- 在互联网早期,这种无状态的网络访问没什么问题,因为早期的互联网一般只是提供一些统一的静态网页,每个用户看到的内容都是一样的
- 但是随着互联网的飞速发展,web 页面进化为 web 应用,作为应用,它需要一种机制来区分不同的用户,进而给不同的用户提供不同的页面和功能
什么是 cookie
- 为了解决上述用户身份识别的问题,HTTP 引入了 cookie 机制来给客户端请求加上状态
- cookie 就是浏览器中的一小块存储空间,它跟域名绑定在一起
- 具体来说,是客户端在发送请求的时候,在请求行里加上 cookie 字段,里面发送一些文本信息
- 服务端收到请求后,从 cookie 里解析出数据,从而完成后续的业务操作
- 服务器也可以往 cookie 里写入内容,在响应请求的时候,在响应行里加上 set-cookie 字段,把要写入的内容发过去
什么是 session
- session 就是用户信息记录,存在服务端,一般放在 Redis
cookie 和 session 的配合
- 既然客户端和服务器可以通过 cookie 完成持久化信息的交互,那完全可以结合二者实现用户身份认证
- 首先,用户在首次访问服务,并且登录后,服务端会生成用户 session
- 接着,服务端会根据这个 session 生成一个匹配的 sessionId,这个 sessionId 用来后续查找出 session
- sessionId 会通过 set-cookie 传给客户端,客户端存在对应域名的 cookie 里
- 下次客户端访问服务端的时候,就会带上 cookie,服务器拿到 cookie 中的 session-id 后,就可以在 Redis 里找到 session 了,从而完成用户身份认证
session 的问题
-
如果用户登录时,生成 session 的服务器跟用户下次访问的服务器不一样,session 就不生效了,用户又要重新登录
-
为了解决这个问题,一般要将 session 集中存储,比如存在分布式的 Redis 集群中,负载均衡机器都要访问集群拿到 session,这又多了一次网络请求,增加了网络时延
-
这对服务端的架构和维护是一个挑战
什么是 token
- 为了解决 session 的上述问题,诞生了 token 的方案,其基本思想是:把必要的用户身份信息和合法性校验信息直接编码打包成一个字符串,然后通过 set-cookie 种在客户端
- 用户登录,服务端校验账号密码,获得用户信息
- 把用户信息、token 配置编码成 token,通过 set-cookie 种在客户端
- 后续用户请求业务接口,通过 cookie 携带 token
- 服务器校验 token 有效性,进行正常业务处理
- 由于不需要存 session,服务器没有了管理 session 集群的压力;但是会有加密解密 token 的算力消耗
- 在复杂系统中,token 可通过 service token(短有效期)、refresh token(长有效期)的分权,同时满足安全性和用户体验
什么是 JWT
-
JSON Web Token:token 的一种标准规范,规定了 token 要携带的信息,加密算法等
token 的优点
- 支持跨域访问,Cookie 是不允许垮域访问的,这一点对 Token 机制是不存在的,前提是传输的用户认证信息通过 HTTP 头传输.
- 无状态,Token 机制在服务端不需要存储 session 信息,因为Token自身包含了所有登录用户的信息,只需要在客户端的 cookie 或本地介质存储状态信息.
- 服务端只需要验证token的安全,不必再去获取登录用户信息,因为用户的登录信息已经在token信息中。
- 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python,PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
token 的问题
- 网络传输的数据量增大:由于token中存储了大量的用户和安全相关的信息,所以比单纯的cookie信息要大很多,传输过程中需要消耗更多流量,占用更多带宽,
- 和所有的客户端认证方式一样,如果想要在服务端控制token的注销有难度,而且也很难解决客户端的劫持问题。
- 由于token信息在服务端增加了一次验证数据完整性的操作,所以比session的认证方式增加了cpu的开销。
单点登录
- 流程图:
- 在 SSO 域下,SSO 不是通过接口把 ticket 直接返回,而是通过一个带 code 的 URL 重定向到系统 A 的接口上,这个接口通常在 A 向 SSO 注册时约定
- 浏览器被重定向到 A 域下,带着 code 访问了 A 的 callback 接口,callback 接口通过 code 换取 ticket
- 这个 code 不同于 ticket,code 是一次性的,暴露在 URL 中,只为了传一下换 ticket,换完就失效
- callback 接口拿到 ticket 后,在自己的域下 set cookie 成功
- 在后续请求中,只需要把 cookie 中的 ticket 解析出来,去 SSO 验证就好
- 访问 B 系统也是一样
鉴权实践如何选型
- 简单系统 cookie session 足矣
- 复杂系统 service token + refresh token
- 多主域名情况,实现单点登录