我尝试使用此处找到的文档:https://pyjwt.readthedocs.io/en/latest/usage.html#retrieve-rsa-signing-keys-from-a-jwks-endpoint与验证相关使用 JWKS 的 JWT 令牌,但使用 Keycloak 发行者对我来说不起作用。
然后我在 Google 上搜索了更多文档,发现了这篇很棒的博客文章:https://renzolucioni.com/verifying-jwts-with-jwks-and-pyjwt/
最后我写下了这段对我有用的代码(也可能对其他人有用,所以我将其粘贴在这里)
token_response = oauth.keycloak.authorize_access_token()
id_token = oauth.keycloak.parse_id_token(token_response)
# Reads the keys from JWK and creates a dictionary with the RSAPublic keys
jwk_uris = requests.get(f'{issuer}/.well-known/openid-configuration').json()["jwks_uri"]
jwks = requests.get(jwk_uris).json()
public_keys = {}
for jwk in jwks['keys']:
kid = jwk['kid']
public_keys[kid] = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk))
if id_token:
logging.debug('logged in ' + id_token['email'])
session['user'] = id_token
token = token_response['access_token']
# get the identifier of the key used from the header token
kid = jwt.get_unverified_header(token)['kid']
# gets the key associated
key = public_keys[kid]
try:
session['resource_access'] = jwt.decode(token, key=key, audience="app_****", algorithms=["RS256"])['resource_access']
except jwt.exceptions.MissingRequiredClaimError as exc:
session['resource_access'] = {}
但最后我对这段代码仍然有问题。为什么我需要指定受众? 我的一些用户没有指定受众所需的资源访问权限,因此令牌不包含“aud”字段,这是可以的。但是当这些用户尝试登录时,解码功能会崩溃并出现 MissingRequiredClaimError。
有没有办法指定所有受众或忽略此字段?似乎必须在解码函数中设置,并且令牌必须包含“aud”字段...
感谢您的回答@jps。
在解码函数中使用没有观众的令牌设置 verify_aud=False 时。我收到“令牌缺少“aud”声明”
# token does not contain an audience. -> "Token is missing the "aud" claim"
token_decoded = jwt.decode(token, key=key, audience="app_****", verify_aud=False, algorithms=["RS256"])
如果我尝试在解码函数中未指定受众的情况下进行解码,则对于不包含受众的令牌,它可以工作!
# token does not contain an audience. -> Works!
token_decoded = jwt.decode(token, key=key, verify_aud=False, algorithms=["RS256"])
但是,如果我的令牌包含观众并且我尝试使用相同的函数进行解码 我收到错误:InvalideAudienceError:受众无效
# token contains the audience -> InvalideAudienceError: Invalid audience
token_decoded = jwt.decode(token, key=key, verify_aud=False, algorithms=["RS256"])
所以看来我必须在不验证其签名的情况下解码令牌以检查令牌中是否有受众。根据是否有观众,我可以通过调用 A 或 B 进行签名验证进行解码。 这没有多大意义,不是吗?
A) 对于有受众的代币
jwt.decode(token, key=key, audience="app_****", algorithms=["RS256"])
B) 对于没有受众的代币
token_decoded = jwt.decode(token, key=key, verify_aud=False, algorithms=["RS256"])
完全像Sai Ramachandran所写,尝试:
header = jwt.get_unverified_header(token)
alg = header["alg"]
kid = header["kid"]
jwk_client = jwt.PyJWKClient(settings.OIDC_OP_JWKS_ENDPOINT)
key = jwk_client.get_signing_key(kid).key
token_decoded = jwt.decode(
token,
key,
algorithms=[alg],
options={"verify_aud": False, "verify_signature": True},
)