Python解析AWS Cognito生成的JWT时出现Could not deserialize key data错误
我有一个AWS Cognito生成的JWT Token,该Token已通过AWS API Gateway认证并成功调用后端AWS Lambda。这是一个有效JWT,在jwt.io上能正常解析,网关认证也没问题,但在Python版Lambda中无法解析。
代码片段
def decodeJWT(authHeader): jwt_token=authHeader.replace('Bearer ','') print(jwt_token) decoded_jwt=jwt.decode(jwt=jwt_token, algorithms="RS256") return decoded_jwt
传入的认证头
Bearer eyJraWQiOiJmUjFiZ21VdzhoNW9RUnZxeVUwZW9jbkhsSU1CbTNZMHRGS3oyVXFLNjVzPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI0NTYzMWVlMy04MWEzLTQ3ZTMtYTEzMS0yNGRhNWY1MmYyMzIiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtZWFzdC0yLmFtYXpvbmF3cy5jb21cL3VzLWVhc3QtMl92YjB4dFBrVlciLCJ2ZXJzaW9uIjoyLCJjbGllbnRfaWQiOiI0MzRubm5nbTFrZnZvMGZtNHVtZzN2OGJ1ZCIsImV2ZW50X2lkIjoiMTVhNWNiMTktNjI0ZS00ZTk0LThiMjktMjI3MmFmYjE4Mjc5IiwidG9rZW5fdXNlIjoiYWNjZXNzIiwic2NvcGUiOiJhd3MuY29nbml0by5zaWduaW4udXNlci5hZG1pbiIsImF1dGhfdGltZSI6MTcwMTE4NjkwMCwiZXhwIjoxNzAxMTkwNTAwLCJpYXQiOjE3MDExODY5MDAsImp0aSI6IjY3M2Y2MTVlLWNmMWMtNDZjMC1iOWY0LTBkMjFiNWI1MThkOSIsInVzZXJuYW1lIjoidGVzdF9hIn0.BKdUHR_al5IAprfZHK9fEC7kthrv6kpyDXdsM6nrUQufVEMliIyz1dk3ruGhDDP4HjW8czlwegoYDX5aqrou3AkXWivsN8JplJELwb3li9XsHOrBhajLgHYwTUdEm5EFQcyxTD22IvkeByHokvzeOW1IakHIR_qdiH4zv9MNfjpy2svuS7imnnik1XLGx0A7eZmq6IDQlfu3v1Bk_ePBpgaOlZBEypmcIaZe5BySbZo6QrLfzASgwfMF0XrJYwtydgq3jz7L3EWEO1IaHT3x-qwZuOC8S4n3m0hr-PZwt7r3akXb75OlFbJMoWRuuWViC-Jpqzm3e72ueNc5BeSIBQ
已确认"Bearer "字符串已被移除,剩余JWT有效。
错误信息
Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/jwt/algorithms.py", line 350, in prepare_key RSAPrivateKey, load_pem_private_key(key_bytes, password=None) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cryptography/hazmat/primitives/serialization/base.py", line 25, in load_pem_private_key return ossl.load_pem_private_key( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 747, in load_pem_private_key return self._load_key( ^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 929, in _load_key self._handle_key_loading_error() File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 984, in _handle_key_loading_error raise ValueError( ValueError: ('无法反序列化密钥数据。数据格式可能不正确、使用了不支持的算法加密,或是不支持的密钥类型(例如带显式参数的EC曲线)。', [<OpenSSLError(code=503841036, lib=60, reason=524556, reason_text=unsupported)>])
环境信息
- Python 3.11.2
- pip 23.3.1
解决方法
问题根源:使用jwt.decode时未提供RS256签名所需的公钥。AWS Cognito的JWT采用非对称加密签名,解析必须用对应的公钥验证,不能直接解析。
修正后的代码
import jwt import requests def get_cognito_public_keys(user_pool_id): # 从Cognito用户池获取公钥集合 url = f"https://cognito-idp.us-east-2.amazonaws.com/{user_pool_id}/.well-known/jwks.json" response = requests.get(url) return response.json()["keys"] def decodeJWT(authHeader): jwt_token = authHeader.replace('Bearer ', '') # 从JWT头部获取密钥ID(kid) header = jwt.get_unverified_header(jwt_token) kid = header["kid"] # 替换为你的Cognito用户池ID user_pool_id = "us-east-2_vb0xtPkVW" keys = get_cognito_public_keys(user_pool_id) # 匹配对应kid的公钥 public_key = None for key in keys: if key["kid"] == kid: public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key) break if not public_key: raise ValueError("未找到匹配的公钥") # 解析并验证JWT的签名和核心声明 decoded_jwt = jwt.decode( jwt_token, public_key, algorithms=["RS256"], issuer=f"https://cognito-idp.us-east-2.amazonaws.com/{user_pool_id}", audience="434nnnmg1kfvo0fm4umg3v8bud" ) return decoded_jwt
注意事项
- 公钥获取:Cognito会为每个用户池提供固定的JWKS公钥地址,需根据JWT头部的
kid匹配对应公钥,确保签名验证正确。 - 声明验证:解析时必须验证
iss(发行者)和aud(受众),防止伪造的JWT被解析。 - 依赖准备:确保Lambda部署包或层包含
pyjwt、cryptography、requests三个依赖包。
内容的提问来源于stack exchange,提问作者ZCode

