【问题标题】:Verify offline an Azure AD generated JWT离线验证 Azure AD 生成的 JWT
【发布时间】:2020-01-17 11:48:18
【问题描述】:

验证 Azure AD 生成的令牌时出现错误。这是当前的设置:

  • 我有一个可以粘贴到https://jwt.io 的令牌,我可以在右侧面板中看到正确的声明。我假设令牌的格式正确。我还可以在标题中看到 kid = piVlloQDSMKxh1m2ygqGSVdgFpAalg: RS256。我将算法类型正确设置为 RS256 以进行验证。

  • 我去https://login.microsoftonline.com/common/discovery/keys寻找公钥,找到了同样的kid = piVlloQDSMKxh1m2ygqGSVdgFpA。所以我复制了对应的公钥(x5c 字段中的字符串)并将其包装成正确的字符串以使其成为 PKCS#8。兼容:

    -----开始证书----- MIIDBTCCAe2gAwIBAgIQMCJcgWf4l5xPpeoEwB7DKDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE5MTExNTAwMDAwMFoXDTI0MTExNDAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANF4YcKZhKTfowwWqZ84RW7bxFNgaSy3Gi85V5uJpU9jMCmZV0VFGptryNFEQ1GESmmuDutgQlkkhjr9ixkOrTA+aFPg6pLn+OG6NYS7nyKgAC1MprLH0bq06y3dH6lQPWQhd3wPP+8UIua9+9JuIfhu9Xs/HhN5cYlT5cEniV0aWuUMxgPAKcG1xolfupYhlOHjFwVN/QOaxcuk3YqGguD+sZ7PiHcJSzFnTkdvD+DtMoW1U6nDf5FuDeAEKJ7JQf7RjiRoViYxZHKrEPHG4iZ+kOhV6DQA16ISTt7ALXVB8gTTF3OvItubk2E3v6sgirgtvdE5Mkd4MTJcO67bgdUCAwEAAaMhMB8wHQYDVR0OBBYEFEXiTeLGkA2LgAjQOrT2KChpgwCgMA0GCSqGSIb3DQEBCwUAA4IBAQA6GqtYZDQzym0yxfL2NnlSbJP/lLhSQOqbPBdN6DWQ/3duk+e08Ix5qy63hzW+qQR0PAkFEcooL5+bdheS66tFJpVejEcqCSKUVvwOUe6GY/ju752dlB7anBB9An362khehCxqydYNS5Igl0rtcP7dKC3ZBn1m2B9ULsyx46iNpfHQHHv9NKU2vVq2CtNc95CFktwjUwlyWMgbfI/DzPX/cC6KnglqsuVVBO7+jIaBmi0XGqudooZkqgIrvnfNMM13Gy78TUNHsCiAQEwZ/L17yNbzotNGxAoPfuXldbD52MQNOsA7 WhH+j8qFWY6gZzTN4NpVtuW4m04TCEFexnTz -----结束证书-----

如果上面看不到,在-----BEGIN CERTIFICATE-----之后和-----END CERTIFICATE-----之前有一个\n

  • 该公钥被复制到它的公钥部分,在我的代码中它是公钥 RSA 密钥。
  • 我也尝试过使用 PKCS#1 进行格式化,但没有获得更多成功

它一直无效。在 jwt.io 和我的代码中甚至都没有过期,显然无效。

假设令牌是正确的,我的方法是否正确?我发现不同的教程以不同的方式准备 .pem。如果我的令牌不正确,除了从中获得索赔外,我该如何检查?

【问题讨论】:

    标签: security jwt azure-active-directory


    【解决方案1】:

    您需要从modulusexponent 生成公钥。

    你可以从https://login.microsoftonline.com/{tenantId_or_commom}/discovery/v2.0/keys得到它们

    这是一个 java 示例供您参考:

        public static PublicKey getPublicKey(String encodedModulus, String encodedExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
            byte[] modulus = Base64.getUrlDecoder().decode(encodedModulus);
            byte[] exponent = Base64.getUrlDecoder().decode(encodedExponent);
    
            StringBuilder sb = new StringBuilder();
            for (byte b : modulus) {
                sb.append(String.format("%02x", b));
            }
            String sm = sb.toString();
    
            sb = new StringBuilder();
            for (byte b : exponent) {
                sb.append(String.format("%02x", b));
            }
            String se = sb.toString();
    
            BigInteger bm = new BigInteger(sm,16);
            BigInteger be = new BigInteger(se,16);
    
            KeyFactory rsa = KeyFactory.getInstance("RSA");
            PublicKey publicKey = rsa.generatePublic(new RSAPublicKeySpec(bm, be));
    
            return publicKey;
        }
    
    
        public static void main(String[] args) throws Exception {
            String modulus = "0XhhwpmEpN-jDBapnzhFbtvEU2BpLLcaLzlXm4mlT2MwKZlXRUUam2vI0URDUYRKaa4O62BCWSSGOv2LGQ6tMD5oU-Dqkuf44bo1hLufIqAALUymssfRurTrLd0fqVA9ZCF3fA8_7xQi5r370m4h-G71ez8eE3lxiVPlwSeJXRpa5QzGA8ApwbXGiV-6liGU4eMXBU39A5rFy6TdioaC4P6xns-IdwlLMWdOR28P4O0yhbVTqcN_kW4N4AQonslB_tGOJGhWJjFkcqsQ8cbiJn6Q6FXoNADXohJO3sAtdUHyBNMXc68i25uTYTe_qyCKuC290TkyR3gxMlw7rtuB1Q";
            String exponent = "AQAB";
            byte[] bytes = getPublicKey(modulus, exponent).getEncoded();
            String encodedString = new String(Base64.getEncoder().encode(bytes));
    
            System.out.println("-----BEGIN PUBLIC KEY-----");
            System.out.println(encodedString);
            System.out.println("-----END PUBLIC KEY-----");
    
            System.out.println();
        }
    

    你会得到如下一些输出:

    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0XhhwpmEpN+jDBapnzhFbtvEU2BpLLcaLzlXm4mlT2MwKZlXRUUam2vI0URDUYRKaa4O62BCWSSGOv2LGQ6tMD5oU+Dqkuf44bo1hLufIqAALUymssfRurTrLd0fqVA9ZCF3fA8/7xQi5r370m4h+G71ez8eE3lxiVPlwSeJXRpa5QzGA8ApwbXGiV+6liGU4eMXBU39A5rFy6TdioaC4P6xns+IdwlLMWdOR28P4O0yhbVTqcN/kW4N4AQonslB/tGOJGhWJjFkcqsQ8cbiJn6Q6FXoNADXohJO3sAtdUHyBNMXc68i25uTYTe/qyCKuC290TkyR3gxMlw7rtuB1QIDAQAB
    -----END PUBLIC KEY-----
    

    然后你可以在 jwt.io 中使用它:

    【讨论】:

    • 超级有帮助,快到了!我在我这边编码,我有和你一样的公钥,这是令人鼓舞的。它也与jwt.io 上的公钥文本框中默认显示的相同(他们是如何得到的?)。尽管如此,它还没有标记为已验证。我不明白接下来要看哪里,它会是一个截断的标记吗?在这种情况下,令牌调试器是否仍会自动找到正确的公钥?
    • 你能分享一个你得到的令牌吗?过期的就可以了。
    • 顺便问一下,请问您是否获得了 Microsoft Graph API 的令牌?
    • 如果获取到 Graph API 的 token,该 token 包含一个 nonce,需要在验证时进行特殊处理。换句话说,只有 Graph 可以验证它。更多相关内容,可以参考 Github 问题页面:#812#609
    • @nlassaux 有一些新发现,请查看上面的 cmets。
    猜你喜欢
    • 1970-01-01
    • 2017-08-25
    • 2021-08-21
    • 1970-01-01
    • 2018-12-25
    • 2017-03-31
    • 2017-09-25
    • 2016-12-02
    • 1970-01-01
    相关资源
    最近更新 更多