ID Token - JWT

我们来继续前两章(OAuth2 总结, 对OpenID Connect的理解)的讨论,进入对JWT的理解。先来简单回顾一下OAuth2和OpenID:

  1. OAuth 2.0 is a specification as to how to issue access tokens
  2. OpenID Connect is a specification as to how to issue ID tokens.

OpenID建立在OAuth之上,完成了认证和授权。而认证和授权的结果就体现在这个ID token之上,而这个ID token通常会是JWT。那么为什么会是JWT呢?我们通过以下几点来逐一解释。

那么既然要体现认证和授权,这个token中应该含有如下信息:

{
  "name": "sashimi",
  "id": "12345",
  "role": "admin",
  "nbf": "some timestamp"
}

JWTRFC 7519 给出了官方定义的一些字段:

  • iss - Issuer 签发人
  • sub - Subject 主题
  • aud - Audience 受众
  • exp - Expiration 过期时间
  • nbf - Not Before 生效时间
  • iat - Issued At 签发时间
  • jti - JWT ID 编号

当然也不限于此,可以根据自己的需要,添加其他字段。到此,我们可以看出JWT提供了ID token所需要的能力。一个完整的JTW是由三部分组成:Header,Payload,Signature。三者之间由.隔开,刚才提到的认证授权的字段就存在于Payload中。
Header中存放的是JTW的元数据,包含签名的算法以及token的类型,如下所示:

{
  "alg": "HS256",
  "typ": "JWT"
}

Signature部分是对前两部分的签名,防止数据篡改。首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature三个部分经过base64序列化为三个字符串,再讲三个字符串由.为间隔拼接成一个字符串返回给客户端。

安全性

ID Token需要有足够的安全性,JWT是如何做到的呢?
刚看到了签名部分,签名的作用只是为了防止数据篡改,而JWT默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。比如认证服务器中使用私钥进行加密,把公钥分发给其他应用服务器,应用服务拿到加密后的token后用公钥解密,获取到JWT,再用签名的秘钥来验证数据是否经过的篡改。

其他备选?

我们来看看还有神马其他备选么?Simple Web Tokens (SWT)和Security Assertion Markup Language Tokens (SAML)。
JWT vs SAML:JWT基于json,而SAML基于XML,在大小上就有足够的优势,更适用于HTML和HTTP。
JWT vs SWT:在安全性上,SWT只支持对称加密,而JWT和SAML支持公私钥的加密方式。

到这里是不是可以看出JWT的优势呢~ OpenID connect + JWT 可以说是现在SSO的方案的一个重要备选方案。

题外话

作为一个mobile developer,也想在这里对比一下原先的简单token模式和SSO中的JWT:
在没有该机制前,我们通常会使用一个随机产生的字符串作为token,认证成功后返回给前端,之后前端的每个请求带上这个token。若后台服务的是个单体应用没有什么问题,请求来了,验证一下token是否有效即可,但当认证服务和其他的应用服务是分离的,怎么做呢?应用服务受到请求,再向认证服务发起一个请求来验证验证token是否合法,是否有权限访问该应用服务。这样做到没有什么问题,只是当服务变多时,比如微服务下,势必会造成认证服务器的压力过大。
在使用该机制后,客户端通过认证服务登录,获得这个JWT,之后其他应用服务自身便可以验证这个token的是否有效,是否有权访问。

看似完美,但也有它自身的问题,我们来看一个场景:权限变更。某用户原先是一个超级管理员,可以访问所有服务,并可进行任意的删除,更改操作,他在这个状态下拿到了JWT。随后,由于权限更改为普通管理员,便不应该具有所有权限,但此时他开始时的JWT被缓存在客户端仍然可用,其他应用服务也并无法知道这个用户的权限已经被更改,后果可想而知了。解决的方式无非是将这个token的有效时间设置的短一些。

你可能感兴趣的:(ID Token - JWT)