JSON Web Token

简介: 本文介绍了 JWT(JSON Web Token)是什么,以及它的一些应用场景。

引言

本文由我的同事 @like 投稿,介绍了 JWT(JSON Web Token)是什么,以及它的一些应用场景。

背景

前段时间看 Kubernetes 认证相关的内容,发现如果 Pod 要和 API Server 交互,需要为该 Pod 创建 ServiceAccount 并绑定相应的角色。比如 Dashboard 的配置文件如下:

# ------------------- Dashboard Service Account ------------------- #

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kubernetes-dashboard-minimal
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard-minimal
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system
# ------------------- Dashboard Deployment ------------------- #

kind: Deployment
apiVersion: apps/v1
metadata:
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
    spec:
      containers:
      - name: kubernetes-dashboard
        image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1
      serviceAccountName: kubernetes-dashboard
---

这里创建了名称为 kubernetes-dashboard 的 ServiceAccount,并绑定到角色 kubernetes-dashboard-minimal,最后在 PodSpecserviceAccountName 字段引用了该 ServiceAccount。

究竟 ServiceAccount 中存放了哪些内容,Kubernetes 背后又做了哪些事情呢?

kubectl -n kube-system get serviceaccount kubernetes-dashboard -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  # ...
secrets:
- name: kubernetes-dashboard-token-sm862

与 ServiceAccount 关联的 Secret 中持有 API Server 的 CA 证书和签名的 JSON Web Token(JWT)。

kubectl -n kube-system get secret kubernetes-dashboard -o yaml
apiVersion: v1
data:
  ca.crt: (APISERVER'S CA BASE64 ENCODED)
  namespace: a3ViZS1zeXN0ZW0=
  token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
  # ...
type: kubernetes.io/service-account-token

这个签名的 JWT 可以用作 bearer token 来认证该 ServiceAccount,即在 HTTP 请求中添加头部 Authorization: Bearer <JWT>。通常情况下,该 Secret 会被挂载到 Pod 下每个容器的 /var/run/secrets/kubernetes.io/serviceaccount 路径,用以 API 访问。

JWT

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

从JWT的定义看出其特点:

  • 信息格式为 json
  • 带签名,保证内容不被篡改

client-credentials-grant.png
目前 JWT 的主要用途是认证,用户成功登录后,认证服务器生成 token 并返回。接下来客户端所有的请求都会携带该 JWT,应用服务器验证 token 的合法性,识别出用户身份。

JWT数据结构

JWT 包含三部分内容,相互之间用 '.' 分隔

  • Header
  • Payload
  • Signature

所以 JWT 字符串看起来如下:

xxxxx.yyyyy.zzzzz

Header

头部由两部分组成: token 类型,为固定值 JWT;使用的签名算法,如 HMAC SHA256 或 RSA。
例子:

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

这个 JSON 对象经过 Base64Url 编码后形成 JWT 的第一部分。

Payload

JWT 的第二部分是 Payload,包含若干条声明(对用户的陈述),这些声明分为三种类型:

  • Registered claims - 预先定义的,包括以下7个字段, 注意:这些声明的名称都是三字符长度,所以说 JWT 是紧凑的

    1. iss (Issuer): 签发人
    2. sub (Subject): 主题
    3. aud (Audience): 受众
    4. exp (Expiration Time): 过期时间
    5. nbf (Not Before): 生效时间
    6. iat (Issued At): 签发时间
    7. jti (JWT ID): 编号
  • Public claims - 第三方扩展的,为避免冲突,使用前参考 IANA JSON Web Token Registry
  • Private claims - 由通信双方自定义的

同样,Payload 部分也要使用 Base64Url 编码。

Signature

Signature 部分是对 Header 和 Payload 的签名,防止数据篡改。
首先,指定一个密钥,该密钥只有认证服务器知道,然后根据 Header 中指定的签名算法,生成签名。

例如你想使用 HMAC SHA256 算法,那么生成签名的公式如下:

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

签名能保证数据在传输过程中不被篡改,如果生成签名时使用的是私钥,能同时验证 JWT 生成方的身份。

注意:签名只保证信息不被篡改,Header 和 Payload 对任何人都是可读的。所以不要放一些敏感信息,除非是加密的。

最后把三部分字符串用逗号连接起来,就得到最终的 JWT。

实例

回到开头的例子,我们拿到了与 ServiceAccount 关联的JWT,利用官方提供的 Debugger 进行解码得到
Header:

{
  "alg": "RS256",
  "kid": ""
}

Payload:

{
  "iss": "kubernetes/serviceaccount",
  "kubernetes.io/serviceaccount/namespace": "kube-system",
  "kubernetes.io/serviceaccount/secret.name": "kubernetes-dashboard-token-sm862",
  "kubernetes.io/serviceaccount/service-account.name": "kubernetes-dashboard",
  "kubernetes.io/serviceaccount/service-account.uid": "91a26bae-6bf1-11e9-aea5-b06ebfc62c4b",
  "sub": "system:serviceaccount:kube-system:kubernetes-dashboard"
}

可以看出,Kubernetes 使用 RS256(RSA Signature With SHA-256)算法生成签名,默认使用的密钥是 API Server 的 TLS 私钥。这里采取 sub 字段的值作为当前的用户名, 进行后续鉴权。

注意: Kubernetes 的 Secret 中保存的数据是 base64 编码的,所以通过 kubectl 拿到的 token 需要先解码

另一个应用场景是 OpenID,在 OAuth 2.0 上扩展的认证协议,不在这里详细阐述。这里以 Google OAuth Playground 为例进行说明,整体过程与 OAuth 2.0 类似: 发送认证请求到 google -> 用户授权返回 code -> 拿 code 换取 access_token。不过这里的 scope 不再是需要授权的资源路径,而是 openid email/profile。认证 URL 可能如下:

https://accounts.google.com/o/oauth2/v2/auth?
 client_id=424911365001.apps.googleusercontent.com&
 response_type=code&
 scope=openid%20email&
 redirect_uri=https://oauth2-login-demo.example.com/code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps://oauth2-login-demo.example.com/myHome&
 login_hint=jsmith@example.com&
 openid.realm=example.com&
 nonce=0394852-3190485-2490358&
 hd=example.com

最后返回的结果除了 access_token,还包括 id_token(由 Google 生成的标明用户身份的 JSON Web Token)。下面让我们看下里面有什么内容
Header:

{
  "alg": "RS256",
  "kid": "57b1928f2f63329f2e92f4f278f94ee1038c923c",
  "typ": "JWT"
}

Payload

{
  "iss": "https://accounts.google.com",
  "azp": "407408718192.apps.googleusercontent.com",
  "aud": "407408718192.apps.googleusercontent.com",
  "sub": "xxx",
  "at_hash": "xxx",
  "name": "xxx",
  "picture": "xxx",
  "given_name": "xxx",
  "family_name": "xxx",
  "locale": "zh-CN",
  "iat": 1576927081,
  "exp": 1576930681
}

可以看到该 JWT 包含了用户名、头像、语言等 profile 信息。

如果我们拿到这样的 JWT,怎么验证其是否是 Google 生成的?

Google把公钥放在 https://www.googleapis.com/oauth2/v3/certs 这个路径上

{
    "alg": "RS256",
    "n": "1Zi0-4bNwZ7gGefz17U2NoKT4xBq-nzAa899teHxB2Q9KVCZYDhbQkpiIrBNg2u8s6TtoSljpq6MJpsKJVJgpT70gDCCgaUsGNYql9-kwWNKd80FlU1sjDEGouUIVEoYHzooPyn9r027KzMnTv5LGRYjxb5lvGnb4UCw5MF_EeSTNpGD7zb0b6juXwBxPi0oIUbQxAcGgH3oS40hXAjJ_U2T3Hln8lBlnVhLbrh-5qF-uoYDxjtAY9XyEJQH_rGiRfXWgBfSM02t9DCB46sQbEMM2iLe7mkGrZtCHR4zbAsAP0s2VGqSmwszNTWqqsdOccbfXp3i_ThkR3pDdTSIQQ",
    "use": "sig",
    "kid": "57b1928f2f63329f2e92f4f278f94ee1038c923c",
    "e": "AQAB",
    "kty": "RSA"
  }

可以看到,其 kid 与前面 JWT 的 header 中的 kid 匹配,下面我们用这个 key 来验证签名的合法性。

String e = <上面key的e字段>;
String n = <上面key的n字段>;
BigInteger modulus = new BigInteger(1, Base64.getUrlDecoder().decode(n));
BigInteger exponent = new BigInteger(1, Base64.getUrlDecoder().decode(e));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(spec);

String jwtStr = <你的id_token>;
Jwt jwt = Jwts.parser().setSigningKey(publicKey).parseClaimsJwt(jwtStr);

执行上述代码后,会显示如下异常信息:

JWT expired at 2019-12-21T12:18:01Z. Current time: 2019-12-22T09:22:02Z, a difference of 75841420 milliseconds.

哈哈 过期啦😂

文章说明

更多有价值的文章均收录于贝贝猫的文章目录

stun

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

创作声明: 本文基于下列所有参考内容进行创作,其中可能涉及复制、修改或者转换,图片均来自网络,如有侵权请联系我,我会第一时间进行删除。

参考内容

[1] JWT Introduction
[2] JSON Web Token入门教程
[3] Kubernetes Authenticating
[4] Google OpenID Connect

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
29天前
|
JSON JavaScript 数据格式
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能。
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能。
43 1
|
3月前
|
JSON 应用服务中间件 nginx
钉钉获取用户token返回的body为空json对象,可能有以下几种情况
钉钉获取用户token返回的body为空json对象,可能有以下几种情况【1月更文挑战第5天】【1月更文挑战第25篇】
33 5
|
23天前
|
XML JSON JavaScript
使用JSON和XML:数据交换格式在Java Web开发中的应用
【4月更文挑战第3天】本文比较了JSON和XML在Java Web开发中的应用。JSON是一种轻量级、易读的数据交换格式,适合快速解析和节省空间,常用于API和Web服务。XML则提供更强的灵活性和数据描述能力,适合复杂数据结构。Java有Jackson和Gson等库处理JSON,JAXB和DOM/SAX处理XML。选择格式需根据应用场景和需求。
|
1月前
|
JSON 大数据 数据格式
web后端-json递归获取key值
web后端-json递归获取key值
|
2月前
|
存储 JSON 安全
解密Web安全:Session、Cookie和Token的不解之谜
解密Web安全:Session、Cookie和Token的不解之谜
77 0
|
3月前
|
存储 JSON 算法
为什么JSON Web Token对于应用程序中的会话管理很有用
为什么JSON Web Token对于应用程序中的会话管理很有用
|
3月前
|
JSON 安全 算法
JSON Web Token(缩写 JWT) 目前最流行、最常见的跨域认证解决方案
JSON Web Token(缩写 JWT) 目前最流行、最常见的跨域认证解决方案
157 0
|
3月前
|
JSON 开发框架 前端开发
动手实现基于 JSON 和 OData 两种数据模型的 Web 应用表格控件行项目的添加和删除
动手实现基于 JSON 和 OData 两种数据模型的 Web 应用表格控件行项目的添加和删除
29 0
|
4月前
|
存储 JSON 中间件
JWT json web token
JWT json web token
39 0
|
6月前
|
JSON 数据格式
ABAP 里生成 JSON Web Token(JWT) 的做法
ABAP 里生成 JSON Web Token(JWT) 的做法
39 0