token认证的设计

本文目录如下

  • 请求Token

  • 生成Token

  • 使用Token

  • 验证Token

  • 扩展阅读

请求Token

在请求Token的API中,有以下参数

Query Parameters

  • service:(neccessary)授权服务的标识,表示要向谁请求token

  • scope:(neccessary)

  • client-id:(optinal)请求token的客户端id,比如docker-daemon发起的请求会将该字段设置为docker,harbor的复制策略中会将该字段设置为harbor-registry-client

Header Parameters

  • Authorization:(optional)携带的用户信息

Response Body

响应body为一个json,有三个字段

  • token:(neccessary)授权服务器返回的带有授权信息的token

  • issued_at:(optional)token的签发时间,UTC标准时间格式

  • expires_in:(optional)token在多少秒以后过期,如果没有说明则默认为60秒

示例

我们可以把上面的token拷贝到网页jwt.io中,查看token的明文形式。

在上面获取token的请求中,没有携带任何的用户信息。不过我们可以使用添加用户信息(用户名与密码)去获取token,如下:

其中YWRtaW46SGFyYm9yMTIzNDU=admin:Harbor12345的base64编码

生成Token

token由三部分内容组成:Header、Payload和Signature。token的形式如下:

Header有三个字段

  • typ:固定为JWT

  • alg:签名算法,常用的有HS256RS256

  • kid:key-id,签名算法中所使用的密钥的ID值

kid的生成有以下三个步骤

1、从签名算法使用的密钥中得到DER编码格式的公钥(public key) 2、对DER格式的公钥做sha256哈希,取前240bit 3、将这240bit使用base32编码,然后四个一组使用冒号:分隔

如下是Header的一个例子

生成kid的详细例子见本文末尾的扩展阅读

Payload

payload中的字段有

  • iss:(Issuer),token的签发者

  • sub:(Subject),正在进行认证的用户的名字,如果是匿名用户则为空

  • aud:(Audience),token的观众,即需要对token进行验证的服务的名字

  • exp:(Expiration),过期时间,在这之后token应该看作是无效的;时间戳格式

  • nbf:(Not Before),token有效的超始时间,在这之前token应当看作是无效的;时间戳格式

  • iat:(Issued At),签发时间;时间戳格式

  • jti:(JWT ID),token的id,(尚不清楚如何生成)

  • access:权限集,下面还有三个字段

    • type

    • name

    • actions

payload的样例如下:

Signature

Header

对header内容去掉空白字符后得到

然后对该字符串进行base64Url编码(base64在线编码网址),得到token-header

base64Url就是先进行base64编码,再把得到的字符串中的+变成-/变成_,去掉=

Payload

payload内容去掉空白字符后得到

然后对该字符串进行base64Url编码,得到token-payload

signature

token-signature的计算方法如下,先对token-header + "." + token-payload做sha256哈希(RS256就是RSA+SHA256),然后再使用RSA的私钥进行签名(sign),最后用base64Url进行编码,得到signature-token

由前面的token-header与token-payload得到的token-signature如下(RSA密钥见扩展阅读)

最后,对token-header、token-payload和token-signature进行组装,得到最终的token

使用Token

在得到token后,我们就可以在API请求的Header中添加token信息,比如下载镜像的manifest

验证Token

当Registry接收到一个携带token的API请求时,Registry需要从以下几个方面来验证Token

  • token的签发者(payload中的iss)是可信的,即和registry的配置参数issuer一致

  • 确保registry是该token的观众,即payload中的aud与registry的配置参数token-service一致

  • 检查payload中的nbfexp确保token在有效期内

  • 检查payload的access字段,确保该token能够访问该API

  • 检查token的签名

扩展阅读

本文中使用到的RSA的私钥为(private_key.pem)

kid的生成

首先从RSA私钥中提取公钥,保存到文件public_key.pem

然后将公钥文件由pem格式生成der格式

然后对der格式的公钥文件做sha256哈希

去掉十六进制的哈希值后四位得到

然后用base32(RFC4648)进行编码(base32在线编码网址),编码后得到

每四位一组,中间用:隔开,得到kid的值

Last updated

Was this helpful?