在面 MoonShot 的时候被问到了这个,当时我只知道认证和鉴权的区别,第一遍听二者的英文名没听懂啥意思,然后就没答出来,我以为是什么其他的芝士点,可恶捏,我得饿补一下芝士点QAQ。
认证(Authentication)
我们常说的登录,这实际上就是认证:Authentication 的完整定义是身份认证,即系统确认你是谁的过程。其本质是用户提供某种可信凭证来证明自己的身份。 平时我们所说的 Jwt 鉴权、Cookie-Session 鉴权这些很多时候讲的就是认证。下面先简单讲讲两个基础认证的手段,后面后统一讲一些框架,比如说 SSO。
Cookie-Session
Cookie 和 Session 算是认证的基本芝士了。众所周知,Http 是一个无状态的协议,想象一下,如果没有一种措施让服务器知道你是谁,就得每次操作都需要输一次账号密码了。虽然 Cookie 和 Session 不是专门为认证所打造的,但是其可以实现简单的认证。
下面是一个简单的 Cookie-Session 的图示:
过程相当的简单,这也正是 Cookie-Session 的优点所在,实现起来相当简单,同时 Session 的鉴权信息是保存在服务器上的,一般来说也比较安全,而缺点也很明显。
缺点:
- 天然非分布式。我们现在的服务器大多都是负载均衡的,而假设我们认证的信息被保存在了服务器 A 上,而后续请求都打到其他服务器上,其他服务器是没有对应的 SessionId 信息的,从而导致无法正常认证。要解决这个问题需要引入其他组件,比如说 Redis 等,进而增加了系统的复杂性。
- 前端未防护 XSS 的情况下,Cookie 可能会被盗取,从而导致安全问题。
- Session 的生命周期管理复杂。一般来说,我们会给 Session 设置一个过期时间,认证时发现过期会拒绝请求,但这些过期的 Session 会造成一定的服务器压力,需要手动清理。
Jwt-Token
JwtToken 全称是 Json-Web-Token,是一种无状态的认证手段。这个相较于 Cookie-Session 会更加符合“潮流”一些。我们来看看用 Jwt 是怎么做认证的。
上面就是一个完整的认证流程,从宏观上来看,似乎只是客户端携带的东西不同了。我认为最重要的不同点是服务器存储的信息粒度的变大,服务器无需再存储每个用户的信息,只需要存储一个服务或者一个业务的密钥,就能解决这个业务上所有用户的认证问题,这一个转变解决了下面这些问题:
- Cookie-Session 的天然不支持分布式的问题,只要一台服务器上有对应服务的密钥,那就 OK。
- 解决了 Session 的生命周期管理的问题,因为服务器无存储压力,服务器只需要看这个 Jwt 里包含的过期时间有没有过期。
如此完美的方案是否有问题呢?有的兄弟,有的:
- Token 过期时间难以把握,太短用户体验不佳,太长 Token 滥用明显。
- Token 如果被劫持,会出现 Token 泄露的安全问题,此时服务器还比较难判断这种情况,而且还很难解决,基本上只能加黑名单解决(这归根是 JwtToken 没法注销的问题,所以难搞)。
- Payload 明文可解码,所以就注定了载荷中数据的类型不能是机密的。
扩展一下 Jwt 的生产过程吧。

SSO
SSO 单点登录,这个也是现在业内比较流行的解决方案。看下面这个例子:
淘宝:
天猫:
我们都知道淘宝和天猫是一家公司的产品,他们之间也是共享账号的。当我在淘宝登录后,进入天猫的时候,就自动登录了,这里采用的就是 SSO 单点登录。具体而言是怎么做的呢?下面用淘宝和天猫举例。
(靠,画的累的一逼)
大概流程就是上面那样,关键点就在当用户第一次用阿里统一认证中心登录的时候,会给用户一个 Cookie,这个 Cookie 中记录有一个 SessionId,当以后访问阿里系产品的时候,会携带这个 Cookie,然后当阿里统一认证中心 Check 这个 SessionId 后,会给对应服务下发一个 Token 或者 Ticket,然后服务拿着这个 Ticket 做一次 Double Check,没问题就可以直接登录成功啦。所以,在第一次登录的时候会比较费劲,后面流程就比较简单了。
所以阿里系的招聘软件什么时候能实现单点登录?这么多个分支,每次都要登录,烦都烦死啦
授权(Authorization)
授权指的是更加细粒度的概念,他决定了你能做什么?其本质是在已知用户身份的前提之下,判断他是否被允许执行某个动作或访问某个资源。拿企业账号来举例,企业账号下可能有多个不同的组,每个组的职责不一样,他们能对资源的操控粒度也就不同。例如后端组可能只能调用资源,不能增删资源,而运维组可以增删资源等。 一般来说授权的主要手段有基于角色的访问控制(RBAC)和 基于属性的访问控制(ABAC)。
RBAC
RBAC 是基于角色的访问控制,是一种很容易理解访问控制手段。其含义就是角色 A 可以干 XXX,角色 B 可以干 XXX。很像公司的架构体系,比如说普通码农可以给公司的代码仓创建分支、提交代码;高级码农就能往主分支 Merge 代码;顶级码农能删库跑路(不是)。
很简单,但是缺点也很明显:
- 粒度不够细。
- 针对于不同的权限组合,需要有多种角色在系统中,可以想象如果系统足够复杂,就会出现角色膨胀的问题。
ABAC
基于属性的访问控制,其不止局限在角色上,其提供一种更细的粒度。比如说,普通码农只能在凌晨 12 点到凌晨 2 点,且系统访问量不超过 100 的时候,发布新版本系统。这里的属性就有三个:
- 普通码农
- 时间
- 系统访问量 通过这样的组合,可以很好的细化鉴权。但是缺点亦存在,就是实现起来相对复杂,对不同的资源权限要赋予或者添加各种各样的属性组合。