认证与授权
1. 概念定义
简单而言,认证 阐述了“你是谁”,授权 表达了“你有权限干什么”:
- 认证(Authentication) :验证用户的身份凭据,例如用户名/用户 ID 和密码,通过这个凭据,系统得以知道你就是你,也就是说系统存在你这个用户。所以,Authentication 被称为身份/用户验证。
- 授权(Authorization) :发生在认证之后,管理用户访问系统(模块)的权限。比如系统中某些特定资源只能被具有特定权限的人访问,有些对系统资源的操作(如删除、添加、更新)只能赋予特定的人。
形象而言,可如下理解:
认证 | 授权 |
---|---|
![]() | ![]() |
认证与授权通常是结合在一起使用的,目的就是为了保护我们系统的安全性。
需要强调的是,对于 HTTP 协议而言,其 header 只有一个 Authorization
字段,这表示 HTTP 协议只能用 Authorization 一词来同时表达认证与授权这种 Web 认证信息,但不要混淆 HTTP 的这个头部字段与认证、授权这两个安全概念。
2. 身份认证方案之:Cookie 与 Session
Cookie
和 Session
都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。
2.1 Cookie
Cookies
是某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。简单来说: Cookie
存放在客户端,一般用来保存用户信息。
下面是 Cookie
的一些应用案例:
- 我们在
Cookie
中保存已经登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了。除此之外,Cookie
还能保存用户首选项,主题和其他设置信息。 - 使用
Cookie
保存SessionId
或者Token
,向后端发送请求的时候带上Cookie
,这样后端就能取到Session
或者Token
了。这样就能记录用户当前的状态了,因为 HTTP 协议是无状态的。 Cookie
还可以用来记录和分析用户行为。举个简单的例子你在网上购物的时候,因为 HTTP 协议是没有状态的,如果服务器想要获取你在某个页面的停留状态或者看了哪些商品,一种常用的实现方式就是将这些信息存放在Cookie
。
2.2 Session
Session
的主要作用是通过服务端记录用户的状态。 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session
之后就可以标识这个用户并且跟踪这个用户了。
Cookie
数据保存在客户端(浏览器端),Session
数据保存在服务器端。相对来说 Session
安全性更高。如果使用 Cookie
的一些敏感信息不要写入 Cookie
中,最好能将 Cookie
信息加密然后使用到的时候再去服务器端解密。
很多时候我们都是通过 SessionID
来关联特定的用户,SessionID
可能会选择存放在 Redis 中。举个例子:
- 用户向服务器发送用户名、密码、验证码用于登陆系统。
- 服务器验证通过后,服务器为用户创建一个
Session
,并将Session
信息存储起来。 - 服务器向用户返回一个
SessionID
,写入用户的Cookie
。 - 当用户保持登录状态时,
Cookie
将与每个后续请求一起被发送出去。 - 服务器可以将存储在
Cookie
上的SessionID
与存储在内存中或者数据库中的Session
信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。

2.3 Session-Cookie 方案的缺点
扩展性不足
Session-Cookie 方案在单体环境是一个非常好的身份认证方案。但是,当服务器水平拓展成多节点时,Session-Cookie 方案就要面临挑战了。
举个例子:假如我们部署了两份相同的服务 A,B,用户第一次登陆的时候 ,Nginx 通过负载均衡机制将用户请求转发到 A 服务器,此时用户的 Session 信息保存在 A 服务器。结果,用户第二次访问的时候 Nginx 将请求路由到 B 服务器,由于 B 服务器没有保存 用户的 Session 信息,导致用户需要重新进行登陆。
当然,硬要解决这个问题的话,也有几个方案可以提供思考:
- 某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session 信息。服务器宕机,其保存的所有 Session 信息就完全丢失了。
- 每一个服务器保存的 Session 信息都是互相同步的,也就是说每一个服务器都保存了全量的 Session 信息。每当一个服务器的 Session 信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。
- 单独使用一个所有服务器都能访问到的数据节点(比如缓存)来存放 Session 信息。为了保证高可用,数据节点尽量要避免是单点。
CSRF 攻击
所谓 CSRF(Cross Site Request Forgery) 一般被翻译为 跨站请求伪造,说简单点就是用你的身份去发送一些不友好的请求 。为什么 Session-Cookie 方案会有 跨站请求伪造 的风险呢?
举个简单的例子:
张三登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个链接写着“科学理财,年盈利率过万”,张三好奇的点开了这个链接,结果发现自己的账户少了 10000 元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转账请求,也就是通过你的 Cookie 向银行发出请求。
<a src=http://www.mybank.com/Transfer?bankId=11&money=10000>科学理财,年盈利率过万</>
由于 Session
认证时 Cookie
中的 SessionId
是由浏览器自动发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。
但是,我们使用 Token
的话就不会存在这个问题。在我们登录成功获得 Token
之后,一般会选择存放在 localStorage
(浏览器本地存储)中。然后前端代码在每个发到后端的请求中加上这个 Token
,由于不是浏览器自动发送的,就不会出现 CSRF 漏洞的问题,因为即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 Token
的,所以这个请求将是非法的。

需要注意的是,不论是 Cookie
还是 Token
都无法避免跨站脚本攻击(Cross Site Scripting)XSS 。
3. 身份认证方案之:Token 机制
基于 token 的鉴权机制类似于 http 协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这意味着基于 token 认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
基于 token 的方案在流程上是这样的:
- 用户使用用户名密码来请求服务器;
- 服务器进行验证用户的信息;
- 验证通过后,服务器通过验证发送给用户一个 token;
- 客户端存储 token,并在每次发送请求时附上这个 token 值;
- 服务端验证 token 值,并返回数据。
这个 token 必须要在每次请求时传递给服务端,通常而言它保存在请求头里。另外,服务端需要支持 CORS(跨域资源共享) 策略,比如设置为 Access-Control-Allow-Origin: *
。
Token 机制的一个流行的实践方案是 JWT(JSON Web Token)。
4. 权限管理模型:RBAC
RBAC(Role-Based Access Control)模型是基于角色的权限控制,通过用户关联角色、角色关联权限的方式间接赋予用户权限。

在 RBAC 模型中,权限与角色相关联,通过把用户分配为适当的角色从而让用户得到这些角色的权限。
如,某系统的权限设计相关的表如下(一共 5 张表,其中 2 张为关联表):

通过该权限模型,就可以创建不同的角色并为不同的角色分配不同的权限范围(菜单),如下:

RBAC 是常用的系统权限控制解决方案模型。
5. 单点登录:SSO
SSO(Single Sign On) 即单点登录,指当用户登陆多个子系统中的其中一个时,就可以(有权限)访问与其相关的其他系统。比如,我们在登陆了京东金融之后,同时能成功跳转到京东的京东超市、京东国际、京东生鲜等子系统。

实现 SSO 后,可以得到以下好处:
- 用户角度:用户能够做到一次登录多次使用,无需记录多套用户名和密码,省心。
- 系统管理员角度:管理员只需维护好一个统一的账号中心就可以了,方便。
- 新系统开发角度:新系统开发时只需直接对接统一的账号中心即可,简化开发流程,省时。
6. 第三方授权:OAuth2.0
OAuth 是一个行业的标准授权协议,主要用来授权第三方应用获取有限的权限。OAuth 2.0 是对 OAuth 1.0 的完全重新设计,2.0 更快,更容易实现,而 1.0 已经被废弃。详情可见:rfc6749。
OAuth 2.0 实际上就是一种授权机制,它的最终目的是为第三方应用颁发一个有时效性的令牌 Token,使得第三方应用能够通过该令牌获取相关的资源。比如,OAuth 2.0 一个常用的场景就是第三方登录,当你的网站接入了第三方登录的时候使用的一般就是 OAuth 2.0 协议;另外,现在 OAuth 2.0 也常见于支付场景(微信支付、支付宝支付)和开发平台(微信开放平台、阿里开放平台等等)。
下图是 Slack OAuth 2.0 第三方登录 的示意图:
