请选择 进入手机版 | 继续访问电脑版
前言

在前后端分离的应用中,后端主要作为 Model 层,为前端提供数据访问 API。为了保证数据安全可靠地在用户与服务端之间传输,实现服务端的认证就显得极为必要。
常见的服务端认证方法有基于 Cookie 的认证,如 session;以及 Token (令牌)认证,如 JWT。前者依赖于 cookie 而实现,在每次请求时都需要带上 cookie ,取出相应字段并与服务器端的进行对比,以实现身份的认证。而后者仅仅需要在 HTTP 的头部附上 token,由服务器 check signature 即可实现,无须担心 cookie 存在的 CORS 问题。具体的实现上,本文选择了大名鼎鼎的 JSON Web Token 技术。
什么是  JSON Web Token?

根据官网的定义,JSON Web Token(以下简称 JWT)是一套开放的标准(RFC 7519),它定义了一套简洁(compact)且 URL 安全(URL-safe)的方案,以安全地在客户端和服务器之间传输 JSON 格式的信息。
它有什么优点?

    体积小(一串字符串)。因而传输速度快传输方式多样。可以通过 HTTP 头部(推荐)/URL/POST 参数等方式传输严谨的结构化。它自身(在 payload 中)就包含了所有与用户相关的验证消息,如用户可访问路由、访问有效期等信息,服务器无需再去连接数据库验证信息的有效性,并且 payload 支持应用定制支持跨域验证,多应用于单点登录
单点登录(Single Sign On):在多个应用系统中,用户只需登陆一次,就可以访问所有相互信任的应用。
为什么选择 JWT?

除了上面说到的优点之外,相比传统的服务端验证, JWT 还有以下吸引点。

1. 充分依赖无状态 API ,契合 RESTful 设计原则(无状态的 HTTP)
首先要理解几个概念:状态,有状态 API 以及无状态 API 。
状态:请求的状态是 client 与 server 交互过程中,保存下来的相关信息,客户端的保存在 page/request/session/application 或者全局作用域中,而 server 的一般存在 session 中。

有状态 API:server 保存了 client 的请求状态, server 通过 client 传递的 sessionID 在其 session 作用域内找到之前交互的信息并应答。

无状态 API:无状态是 RESTful 架构设计的一个非常重要的原则。无状态 API 的每一个请求都是独立的,它要求客户端保存所有需要的认证信息,每次发请求都要带上自己的状态,以 url 的形式提交包含 cookies 等状态的数据。
JWT 的设计契合无状态原则:用户登录之后,服务器会返回一串 token 并保存在本地,在这之后的服务器访问都要带上这串 token,来获得访问相关路由、服务及资源的权限。比如单点登录就比较多地使用了 JWT,因为它的体积小,并且经过简单处理(使用 HTTP 头带上 Bearer 属性 + token )就可以支持跨域操作。

2. 易于实现 CDN,将静态资源分布式管理
在传统的 session 验证中,服务端必须保存 session ID,用于与用户传过来的 cookie 验证。而一开始 sessionID 只会保存在一台服务器上,所以只能由一台 server 应答,就算其他服务器有空闲也无法应答,无法充分利用到分布式服务器的优点。  JWT 依赖的是在客户端本地保存验证信息,不需要利用服务器保存的信息来验证,所以任意一台服务器都可以应答,服务器的资源也能被较好地利用。

3. 验证解耦,随处生成
无需使用特定的身份验证方案,只要拥有生成 token 所需的验证信息,在何处都可以调用相应接口生成 token,无需繁琐的耦合的验证操作,可谓是一次生成,永久使用。

4. 比 cookie 更支持原生移动端应用
原生的移动应用对 cookie 与 session 的支持不够好,而对 token 的方式支持较好。(这一块我不了解,不多说,以免误导)

除此之外,JWT 可靠的结构化的标准,也是我们选择它的一大原因。基于 Node.js 有 express-jwt、koa-jwt 等可供选用。
JWT 工作原理

Server端的认证神器——JWT(一)-1.jpg

首先,某 client 使用自己的账号密码发送 post 请求 login,由于这是首次接触,服务器会校验账号与密码是否合法,如果一致,则根据密钥生成一个 token 并返回,client 收到这个 token 并保存在本地。在这之后,需要访问一个受保护的路由或资源时,只要附加上 token(通常使用 Header 的 Authorization 属性)发送到服务器,服务器就会检查这个 token 是否有效,并做出响应。
JWT 组成

[code][/code]JWT 是由 . 连接的三部分组成。
第一部分是经过 Base64 编码的 Header。Header 是一个 JSON 对象,对象里有一个值为 “JWT” 的 typ 属性,以及 alg 属性,值为 HS256,表明最终使用的加密算法是 HS256。
第二部分是经过 Base64 编码的 Payload。Payload 被定义为实体的状态,就像 token 自身附加元数据一样,claim 包含我们想要传输的信息,以及用于服务器验证的信息,一般有 reserved/public/private 三类。
第三部分是 $Signature。它由 Header 指定的算法 HS256 加密产生。该算法有两个参数,第一个参数是经过 Base64 分别编码的 Header 及 Payload 通过 . 连接组成的字符串,第二个参数是生成的密钥,由服务器保存。
注意:从这里我们可以看出,JWT 仅仅是对 payload 做了简单的 sign 和 encode 处理,并未被加密,并不能保证数据的安全性,所以建议只在其中保存非敏感的用于身份验证的数据。
服务端验证

服务端接收到 token 之后,会逆向构造过程,decode 出 JWT 的三个部分,这一步可以得到 sign 的算法及 payload,结合服务端配置的 secretKey,可以再次进行 $Signature 的生成得到新的 $Signature,与原有的 $Signature 比对以验证 token 是否有效,完成用户身份的认证,验证通过才会使用 payload 的数据。 (过程详见node-jsonwebtoken、node-jws、node-jwa)
如你所见,服务端最终只是为了验证 $Signature 是否仍是自己当时下发给 client 的那个,如果验证通过,则说明该 JWT 有效并且来自可靠来源,否则说明可能是对应用程序的潜在攻击,以此完成认证。
感谢以下参考文章:
- Json Web Token Introduction
- 使用Json Web Token设计Passport系统
- 深入RESTful无状态原则
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|翁笔

© 2001-2018 Wengbi.com

返回顶部