JWT - JSON Web Token
JSON Web Token 是一个开放标准( RFC 7519 ),它定义了如何对JSON数据进行签名和加密。缩写是JWT。此信息可以验证和信任,因为它是数字签名的。JWT 可以使用密钥(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
概述
在 JWT 中,可以在令牌中保存任意信息(投诉),例如,服务器可以生成一个令牌,其中包含“以管理员身份登录”的信息给客户端。客户端可以使用令牌来证明他以管理员身份登录。令牌使用一方(通常是服务器)或双方(另一方提供公钥)的私钥签名,并且可以验证颁发的令牌是否合法。
JWT 令牌具有紧凑的设计并且是URL安全的,使其易于使用,尤其是对于Web 浏览器中的单点登录(SSO)。令牌一般存储认证提供者和服务提供者认证的用户身份信息,以及每个服务所需的信息。
JWT 基于其他基于 JSON 的开放标准,JSON Web Signature ( JWS, RFC 7515 )和JSON Web Encryption ( JWE , RFC 7516 )
- 紧凑(Compact) :由于传送的数据小,JWT 可以通过GET、POST 和 放在 HTTP 的 header 中,同时也是因为小也能传送的更快。
- 自包含(self-contained) : Payload 中能够包含用户的信息,避免数据库的查询。
使用场景
- 授权:这是使用 JWT 最常见的场景。用户登录后,每个后续请求都将包含 JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小并且能够在不同的域中轻松使用。
- 信息交换:JSON Web 令牌是在各方之间安全传输信息的好方法。因为可以对 JWT 进行签名(例如,使用公钥/私钥对),所以您可以确定发件人就是他们所说的那个人。此外,由于使用标头和有效负载计算签名,您还可以验证内容没有被篡改。
结构
在其紧凑的形式中,JSON Web Tokens 由以点 ( .) 分隔的三部分组成,它们是:
- Header 头部
- Payload 负载
- Signature 签名
因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz
Header 头部
标头通常由两部分组成:令牌的类型,即 JWT,以及正在使用的签名算法,例如 HMAC SHA256 或 RSA。
|
|
然后,这个 JSON 被Base64Url编码以形成 JWT 的第一部分。
Payload 负载
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的陈述。索赔分为三种类型:注册索赔、公开索赔和私人索赔。
- 注册声明:这些是一组预定义的声明,它们不是强制性的,但建议使用,以提供一组有用的、可互操作的声明。JWT 规定了7个官方字段,供选用。
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
- 公共声明:这些可以由使用 JWT 的人随意定义。但是为了避免冲突,它们应该在IANA JSON Web Token Registry中定义,或者定义为包含抗冲突命名空间的 URI。
- 私人声明:这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公共声明。
|
|
然后对有效负载进行Base64Url编码以形成 JSON Web 令牌的第二部分。
Signature 签名
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
例如,如果您想使用 HMAC SHA256 算法,签名将通过以下方式创建:
|
|
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
Base64URL
前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。 JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。
Header.Payload.Signature
输出是三个用点分隔的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更紧凑。
下面显示了一个 JWT,该 JWT 具有先前的标头和有效负载编码,并使用秘密签名。
如果您想玩 JWT 并将这些概念付诸实践,您可以使用 jwt.io Debugger 来解码、验证和生成 JWT。
如何工作
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。
此后,客户端每次与服务器通信,每当用户想要访问受保护的路由或资源时,可以把它放在 Cookie 里面自动发送,但是这样不能跨域,更好的做法是在Authorization 标头中使用 Bearer 模式。
|
|
另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。
请注意,如果您通过 HTTP 标头发送 JWT 令牌,则应尽量防止它们变得太大。某些服务器不接受超过 8 KB 的标头。如果您尝试在 JWT 令牌中嵌入太多信息,例如通过包含所有用户的权限,您可能需要其他解决方案,例如Auth0 Fine-Grained Authorization。
如果令牌在Authorization标头中发送,则跨域资源共享 (CORS) 不会成为问题,因为它不使用 cookie。
JWT 的几个特点
- JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
- JWT 不加密的情况下,不能将秘密数据写入 JWT。
- JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
- JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
- JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
- 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。