我正在使用Keycloak来处理登录并生成JWT令牌。我需要能够验证我发送到我的REST API服务的访问令牌。最佳做法是使用JWT秘密直接验证令牌,而不是将其发送到Keycloak服务器进行验证。有很多Java例子可以做到这一点,但我需要能够使用python或ruby来验证这一点。
我尝试了以下python签名验证,但收到ValueError: Could not unserialize key data.
错误我还尝试在https://jwt.io调试器中输入公钥,但也获得了无效签名。
#!/usr/bin/env python3
import jwt
# Public key from Keycloak realm -> Keys -> Public Key -> (view)
public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu77nUtVw7SIIcUTSiStzMPB7BGB/9eS+CpppsUaiyZyWCXlrALT3YdqneSlpX4Ta+0wvhOkKQtoSS8dCH8GIi7esAmfdHetHfRgeDXHAlXo8HIzshUzODg3ysT7j+Ha3eJsO+LNS/omHDhsarP8Z2eThW876iKJCCc/mB76a6u1e4Id+52K5lG++m8Pn4Gs+cqd2sKUKcMJ9CkJ6dBIdGlXHMoOHj4C33SPrEG/vEBv5cu0l5PP3RiBAuaZHpLKzfIiaLOpj/k4dD/weVt5gwTIJn16AEgPD7173Xef0HgoPlQInDFrJwsGpYCnIPZWSxRbvjKkya2Auj0QZyMCrXwIDAQAB"
# Keycloak JWT RS256 access-token
access_token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0LVlJOUlVc2R6NGM0SHoycXczT0xXZ0I0eHc2eFd4T29XdktVT2FvV3FzIn0.eyJqdGkiOiJjYzZkMjM5OS04ZmU5LTQzMWItYjZjMS05NWQxMWUxN2FiZGQiLCJleHAiOjE0ODE1NTQ2NTksIm5iZiI6MCwiaWF0IjoxNDgxNTU0MzU5LCJpc3MiOiJodHRwczovL3BtaS1rZXljbG9hay5zYnZpbXByb3Zlci5jb20vYXV0aC9yZWFsbXMvT3BlbkJFTCIsImF1ZCI6ImJlbG1nciIsInN1YiI6ImU1ODc2OGQxLWU3ODktNGU3Yi04ZGVlLWJjMzYxNzFkZDNhZCIsInR5cCI6IkJlYXJlciIsImF6cCI6ImJlbG1nciIsIm5vbmNlIjoiMzc2ZDdjZmUtZGZkNC00Yzg5LWJlZGEtZTlmOWNmYWNlMTNkIiwiYXV0aF90aW1lIjoxNDgxNTUzMTY0LCJzZXNzaW9uX3N0YXRlIjoiN2E2OTEzYzItZWJkZC00MTc2LWI4YTAtZDc2NzVhNDZkNmJjIiwiYWNyIjoiMSIsImNsaWVudF9zZXNzaW9uIjoiOTMyNGMzMjAtMmE4Zi00ODBlLTg5MjItZGQxNmFmMDQxZDdmIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJXaWxsaWFtIEhheWVzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoid2lsbGlhbS5zLmhheWVzQGdtYWlsLmNvbSIsImdpdmVuX25hbWUiOiJXaWxsaWFtIiwiZmFtaWx5X25hbWUiOiJIYXllcyIsImVtYWlsIjoid2lsbGlhbS5zLmhheWVzQGdtYWlsLmNvbSJ9.Q7s-qTcJyH69Ebof8pQI1kZzeT8olwQnRJ06uas5TP2isacxOheHnJ9ixEvqTrr-iefmYMwx41jM68NCs6l8IBNHqv7t5-ediizx4ianMiXr7oZ_1oAT9hkLyrpv9iF2IZBtzNJz0GQAnDYe1moLOLuzqwvcUaWgmzRY95xvzo4kbE8OkeZiMpD_cDmp3_vKOsdn3B6ybJ9TXtea55A29pQzsvAM_6lHeyxTCisipOtu_ubnUOamkYSpxLwWZXgI1w7iz-igt-n7xtlFhUpra239yn9uly9iuBtlgnc3TFDmZn-XRq_PODDJNJeaQXDRaDqnRQhXsoObxCaPqXDQ3A"
access_token_json = jwt.decode(access_token, public_key)
print(access_token_json)
答案 0 :(得分:3)
要验证访问令牌,我执行了以下操作:
我重置了到期时间,因此我不必担心超时是一个复杂的因素。
我必须将BEGIN / END页眉/页脚添加到pubkey(其中有两个不同的版本,基于pubkey的编码-eg'BEGIN RSA PUBLIC KEY'不是正确的版本Keycloak pubkey编码):
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu77nUtVw7SIIcUTSiStzMPB7BGB/9eS+CpppsUaiyZyWCXlrALT3YdqneSlpX4Ta+0wvhOkKQtoSS8dCH8GIi7esAmfdHetHfRgeDXHAlXo8HIzshUzODg3ysT7j+Ha3eJsO+LNS/omHDhsarP8Z2eThW876iKJCCc/mB76a6u1e4Id+52K5lG++m8Pn4Gs+cqd2sKUKcMJ9CkJ6dBIdGlXHMoOHj4C33SPrEG/vEBv5cu0l5PP3RiBAuaZHpLKzfIiaLOpj/k4dD/weVt5gwTIJn16AEgPD7173Xef0HgoPlQInDFrJwsGpYCnIPZWSxRbvjKkya2Auj0QZyMCrXwIDAQAB -----END PUBLIC KEY-----
## Python script #!/usr/bin/env python3 import jwt public_key = """-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu77nUtVw7SIIcUTSiStzMPB7BGB/9eS+CpppsUaiyZyWCXlrALT3YdqneSlpX4Ta+0wvhOkKQtoSS8dCH8GIi7esAmfdHetHfRgeDXHAlXo8HIzshUzODg3ysT7j+Ha3eJsO+LNS/omHDhsarP8Z2eThW876iKJCCc/mB76a6u1e4Id+52K5lG++m8Pn4Gs+cqd2sKUKcMJ9CkJ6dBIdGlXHMoOHj4C33SPrEG/vEBv5cu0l5PP3RiBAuaZHpLKzfIiaLOpj/k4dD/weVt5gwTIJn16AEgPD7173Xef0HgoPlQInDFrJwsGpYCnIPZWSxRbvjKkya2Auj0QZyMCrXwIDAQAB -----END PUBLIC KEY-----""" access_token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0LVlJOUlVc2R6NGM0SHoycXczT0xXZ0I0eHc2eFd4T29XdktVT2FvV3FzIn0.eyJqdGkiOiJiMGFhZDllMC1lYmU5LTQ4ZDQtYTcxNC1iMWMyNjg4NmM2MDciLCJleHAiOjE0ODE5ODE0ODQsIm5iZiI6MCwiaWF0IjoxNDgxODk1MDg0LCJpc3MiOiJodHRwczovL3BtaS1rZXljbG9hay5zYnZpbXByb3Zlci5jb20vYXV0aC9yZWFsbXMvT3BlbkJFTCIsImF1ZCI6ImJlbG1nciIsInN1YiI6ImU1ODc2OGQxLWU3ODktNGU3Yi04ZGVlLWJjMzYxNzFkZDNhZCIsInR5cCI6IkJlYXJlciIsImF6cCI6ImJlbG1nciIsIm5vbmNlIjoiMzI3NjRhYWUtZmM1NC00MDlkLTgxM2EtNjhhNmM4YTNhYzI2IiwiYXV0aF90aW1lIjoxNDgxODk1MDgzLCJzZXNzaW9uX3N0YXRlIjoiMWQwNDMyMDQtNWNkYy00OTVjLWJlZWUtODIwZWJiMmRlNWUzIiwiYWNyIjoiMSIsImNsaWVudF9zZXNzaW9uIjoiMmEzZWY1MzgtN2MxOS00YzE3LTlmZTctYjQ3ZGNjNmM0ODQyIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJXaWxsaWFtIEhheWVzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoid2lsbGlhbS5zLmhheWVzQGdtYWlsLmNvbSIsImdpdmVuX25hbWUiOiJXaWxsaWFtIiwiZmFtaWx5X25hbWUiOiJIYXllcyIsImVtYWlsIjoid2lsbGlhbS5zLmhheWVzQGdtYWlsLmNvbSJ9.DfC1c6BVBZ8Bgwu6CYGBsWp4T0dqltwAQ84E1Q0LdjFxvtVeDOF8rBIdgkr7rMCHObZWsEotljSR4BZzCvfDNmdk_25sedvi-ZHXTP0-nSeHczIXBstZ8p257A6-fEiIcG5CRoClHMI317bVGjNkzAV7l8kuBhr0bfrDedxpvKo3EQah4MrOF7-JXQGPAWlLDV1E9zsrT99Vm_XL58M-ur8q7N-B-CmOBV2GGsMEosTDK_-U-mattEN6PMNiG004Ryg0iPDM4-kr1AQsPE_wHBYf81_-vrqs7ec--0ShJYdC8-eBbuf9xVixNQVPRl7mnktaKA19YXdzdCwcQa6crw" access_token_json = jwt.decode(access_token, public_key, audience='belmgr') print(access_token_json)
答案 1 :(得分:2)
我想补充这些知识,以防其他人陷入困境。
直接从Keycloak领域->密钥->公共密钥->(视图)复制的public_key值不起作用。取而代之的是,我必须使用URL获取由Keycloak为该领域公开的公钥:
https://<< my keycloak url >>/auth/realms/<< my realm >>/
此网址返回的json包含领域“ my realm”的“ public_key”值。按照所选答案中建议的方式使用公钥的
但是,您还需要确保您的受众价值与解码调用正确。对于我来说,值“ belmgr”。我通过使用jwt.io并解码了access_token来找到了所需的听众,并且在有效载荷数据中找到了:
{ ..."aud": "account",... }
在观众工作时使用“帐户”。
# wrong audience - FAIL
access_token_json = jwt.decode(access_token, public_key, audience='belmgr')
# right audience - SUCCESS
access_token_json = jwt.decode(access_token, public_key, audience='account')