JSON Web Tokens (缩写:jwt)是一种无状态 JSON 格式网络令牌。
通常用户认证需要登陆。伺服器收到资料后在 db 找用户,找到就创建一个会话,再签发一个会话 cookie 给用户。用户之后每次访问就要用这个 cookie。伺服器读这个 cookie, 然后再从以创建的会话资料中配对这个 cookie,然后再继续其它。
问题是 API 端点不用 cookie 的。还有如果你有多个伺服器(cluster),伺服器 s 之间同步用户的会话 cookie 比较难实施。而且,还有 CSRF 的风险。
JWT 可以解决跨伺服器认证问题
JWT 的数据分为三个类别:header,data,signature。
- header:描述算法和令牌类别。
- data:JSON object,可以是任何东西
- signature:加密后的密钥,
HMACSHA256("header.data", secret)
,secret 伺服器才有的密钥
header 和 data 都是用简单的 base64 进行编码。每个类别用一个 .
分开。
例子:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
用户获取令牌后,每次发出 HTTP Request 添加这个令牌,例如 HTTP Header 的Authorization: Bearer xxx...
,
伺服器就做一个校验(validate)。令牌是否过期,异常,或者缺少等等。一切没问题,就可以继续进行做你要的东西。
可以解决跨伺服器认证问题?每台伺服器只要用同样的密钥就可以校验令牌,不需要从已创建的会话资料中认证你的登陆状态。
JWT 最大的缺点(我认为)
【1】需要全面 HTTPS 支持。JWT 数据中的 data 是没加密的,简单的 base64url 编码而已 可以说是明文了。数据传输过程中有第三方截取令牌,也就是第三方可以用令牌来登陆做其它事(也就是已盗号了~)。所以 JWT 的 data 尽量限制一下,避免一些敏感的资料,例如密码这类。
【2】官方说的,令牌 size 会变得很大。想想每次 HTTP 请求都要额外的资料。
HTTP Header 方式:
Authorization: Bearer JWT_TOKEN
又或者 query 参数方式:?token=
POST /profile?name=JoJo&token=JWT_TOKEN
【3】令牌存储方式:没什么可以选,只有 local storage、session storage 和 cookie。是的,cookie 是可用的方式来存储 jwt 令牌,记得伺服器不会用 cookie 来认证,所以 HTTP Request 带有 cookie 也没所谓。
总结
JWT 已经广泛应用了。Google、Facebook、Firebase 这些公司的 oAuth 登陆都是用了这个科技。当然,不管是 Node、PHP、Python、Ruby、还是 .NET 你用到的都差不多支持了。
JWT 适合智能手机的 app 客戶端。手机 app 不用 cookie 也不支持 cookie 认证。当然,最重要的是阻止 CSRF。