JWT 令牌身份验证使用 python 请求 DockerHub
JWT Token auth using python requests for DockerHub
我发现可以通过 JavaScript API, and figured this would be a fun excuse to learn the requests
package for python. The JavaScript API definitely works, e.g. using this simple docker image.
编辑 DockerHub 存储库的 full_description
JS API 基本上可以
- Send a
POST
request 到 https://hub.docker.com/v2/users/login
使用用户名和密码。服务器响应 token
.
- Send a
PATCH
request 到特定的 https://hub.docker.com/v2/repositories/{user or org}/{repo}
,确保 header 有 Authorization: JWT {token}
,在这种情况下 body 的 {"full_description":"...value..."}
].
令人不安的是,python 端的 PATCH
请求从服务器返回 200 响应(如果您故意设置错误的身份验证令牌,您将按预期被拒绝)。但它的响应实际上包含当前信息(不是补丁信息)。
我唯一的"discoveries":
如果加上debug logging stuff,就有301了。但是javascript这边是一样的URL,所以没关系?
send: b'{"full_description": "TEST"}'
reply: 'HTTP/1.1 301 MOVED PERMANENTLY\r\n'
通过在requests
中执行POST
收到的令牌与我GET
到auth.docker.io
一样在 Getting a Bearer Token section here 中描述。 值得注意的是,我没有指定密码(只是 curl -X GET ...
)。 这不是真的。他们是不同的,我不知道我怎么认为他们是一样的。
第二个让我觉得我少了一步。就像我需要解码令牌之类的?我不知道还能做什么,尤其是 PATCH
的 200
响应,尽管没有任何变化。
代码:
import json
from textwrap import indent
import requests
if __name__ == "__main__":
username = "<< SET THIS VALUE >>"
password = "<< SET THIS VALUE >>"
repo = "<< SET THIS VALUE >>"
base_url = "https://hub.docker.com/v2"
login_url = f"{base_url}/users/login"
repo_url = f"{base_url}/repositories/{username}/{repo}"
# NOTE: if I use a `with requests.Session()`, then I'll get
# CSRF Failed: CSRF token missing or incorrect
# Because I think that csrftoken is only valid for login page (?)
# Get login token and create authorization header
print("==> Logging into DockerHub")
tok_req = requests.post(login_url, json={"username": username, "password": password})
token = tok_req.json()["token"]
headers = {"Authorization": f"JWT {token}"}
print(f"==> Sending PATCH request to {repo_url}")
payload = {"full_description": "TEST"}
patch_req = requests.patch(repo_url, headers=headers, json=payload)
print(f" Response (status code: {patch_req.status_code}):")
print(indent(json.dumps(patch_req.json(), indent=2), " "))
事实证明,JWT {token}
身份验证一直有效。显然,您需要在 URL 末尾添加一个 /
。没有它,什么也不会发生。哈哈!
# ----------------------------------------------------V
repo_url = f"{base_url}/repositories/{username}/{repo}/"
正如预期的那样,PATCH
然后使用更新的描述而不是旧描述进行响应。太棒了!
重要说明:截至 2020 年 1 月 15 日,这对我有用,但在我的探索中,我遇到了 this dockerhub issue,这似乎表明如果您的帐户启用了 2FA,您将无法再编辑description
使用 PATCH
请求。我的帐户上没有 2FA,所以我可以(显然)。还不清楚它的未来会怎样。
相关说明:JWT 令牌一直保持不变,因此对于像我这样的网络新手,请不要共享这些 ;)
使用 requests.Session() 时与您的 CSRF 问题相关的其他信息:
在这种情况下发出请求时,Docker Hub 似乎无法识别名为 header/cookie 的 csrftoken
(即将到来的 cookie 的默认名称)。
相反,当在以下请求中使用 header X-CSRFToken
时,CSRF 被识别为有效。
也许原因是 cookie-to-header token pattern.
使用登录响应的 cookie 更新 session header 后
s.headers.update({"X-CSRFToken": s.cookies.get("csrftoken")})
无需再为进一步的请求手动设置 JWT 令牌 - 令牌已作为 cookie 使用。
抱歉,没有足够的权限来发表评论,但我认为这足够相关。
我发现可以通过 JavaScript API, and figured this would be a fun excuse to learn the requests
package for python. The JavaScript API definitely works, e.g. using this simple docker image.
full_description
JS API 基本上可以
- Send a
POST
request 到https://hub.docker.com/v2/users/login
使用用户名和密码。服务器响应token
. - Send a
PATCH
request 到特定的https://hub.docker.com/v2/repositories/{user or org}/{repo}
,确保 header 有Authorization: JWT {token}
,在这种情况下 body 的{"full_description":"...value..."}
].
令人不安的是,python 端的 PATCH
请求从服务器返回 200 响应(如果您故意设置错误的身份验证令牌,您将按预期被拒绝)。但它的响应实际上包含当前信息(不是补丁信息)。
我唯一的"discoveries":
如果加上debug logging stuff,就有301了。但是javascript这边是一样的URL,所以没关系?
send: b'{"full_description": "TEST"}' reply: 'HTTP/1.1 301 MOVED PERMANENTLY\r\n'
通过在这不是真的。他们是不同的,我不知道我怎么认为他们是一样的。requests
中执行POST
收到的令牌与我GET
到auth.docker.io
一样在 Getting a Bearer Token section here 中描述。 值得注意的是,我没有指定密码(只是curl -X GET ...
)。
第二个让我觉得我少了一步。就像我需要解码令牌之类的?我不知道还能做什么,尤其是 PATCH
的 200
响应,尽管没有任何变化。
代码:
import json
from textwrap import indent
import requests
if __name__ == "__main__":
username = "<< SET THIS VALUE >>"
password = "<< SET THIS VALUE >>"
repo = "<< SET THIS VALUE >>"
base_url = "https://hub.docker.com/v2"
login_url = f"{base_url}/users/login"
repo_url = f"{base_url}/repositories/{username}/{repo}"
# NOTE: if I use a `with requests.Session()`, then I'll get
# CSRF Failed: CSRF token missing or incorrect
# Because I think that csrftoken is only valid for login page (?)
# Get login token and create authorization header
print("==> Logging into DockerHub")
tok_req = requests.post(login_url, json={"username": username, "password": password})
token = tok_req.json()["token"]
headers = {"Authorization": f"JWT {token}"}
print(f"==> Sending PATCH request to {repo_url}")
payload = {"full_description": "TEST"}
patch_req = requests.patch(repo_url, headers=headers, json=payload)
print(f" Response (status code: {patch_req.status_code}):")
print(indent(json.dumps(patch_req.json(), indent=2), " "))
事实证明,JWT {token}
身份验证一直有效。显然,您需要在 URL 末尾添加一个 /
。没有它,什么也不会发生。哈哈!
# ----------------------------------------------------V
repo_url = f"{base_url}/repositories/{username}/{repo}/"
正如预期的那样,PATCH
然后使用更新的描述而不是旧描述进行响应。太棒了!
重要说明:截至 2020 年 1 月 15 日,这对我有用,但在我的探索中,我遇到了 this dockerhub issue,这似乎表明如果您的帐户启用了 2FA,您将无法再编辑description
使用 PATCH
请求。我的帐户上没有 2FA,所以我可以(显然)。还不清楚它的未来会怎样。
相关说明:JWT 令牌一直保持不变,因此对于像我这样的网络新手,请不要共享这些 ;)
使用 requests.Session() 时与您的 CSRF 问题相关的其他信息:
在这种情况下发出请求时,Docker Hub 似乎无法识别名为 header/cookie 的 csrftoken
(即将到来的 cookie 的默认名称)。
相反,当在以下请求中使用 header X-CSRFToken
时,CSRF 被识别为有效。
也许原因是 cookie-to-header token pattern.
使用登录响应的 cookie 更新 session header 后
s.headers.update({"X-CSRFToken": s.cookies.get("csrftoken")})
无需再为进一步的请求手动设置 JWT 令牌 - 令牌已作为 cookie 使用。
抱歉,没有足够的权限来发表评论,但我认为这足够相关。