【问题标题】:How do I verify a JWT signature for an Azure B2C id token in Java?如何在 Java 中验证 Azure B2C id 令牌的 JWT 签名?
【发布时间】:2016-07-06 17:39:19
【问题描述】:

如何在 Java 中验证 Azure B2C id 令牌的 JWT 签名?我已使用 google open-id connect 成功验证了签名,但尚未成功验证 Microsoft Azure B2C jwt id 令牌的签名。我在这里使用了示例 B2C 游乐场应用程序 https://aadb2cplayground.azurewebsites.net/ 。注册并编辑我的个人资料后,我捕获了这个 id 令牌。

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJiYjJhMmUzYS1jNWU3LTRmMGEtODhlMC04ZTAxZmQzZmMxZjQiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83NzU1MjdmZi05YTM3LTQzMDctOGIzZC1jYzMxMWY1OGQ5MjUvIiwiaWF0IjoxNDU4NDMzMDIzLCJuYmYiOjE0NTg0MzMwMjMsImV4cCI6MTQ1ODQzNjkyMywiYW1yIjpbInB3ZCJdLCJpcGFkZHIiOiI3NC4xMzkuMjEzLjE3NSIsIm5hbWUiOiJib2I1Iiwibm9uY2UiOiJMNlNvekpjeVVEc2lYQ2t0NVQwN1NBPT0iLCJvaWQiOiJjNjc0NDA1Yy05ZGIxLTRmN2EtYTIwMy1jNzZkNDk1Zjk5ZDAiLCJwdWlkIjoiMTAwM0JGRkQ5NkQ0NThCMSIsInN1YiI6InozTGRJOWUtSFlWeXpCSl9sOE9RTndWYnRQM3BnbHBwREo3NjJ2TmEycFkiLCJ0aWQiOiI3NzU1MjdmZi05YTM3LTQzMDctOGIzZC1jYzMxMWY1OGQ5MjUiLCJ1bmlxdWVfbmFtZSI6InJib290aF9jYWxsaWJyaXR5LmNvbSNFWFQjQGZhYnJpa2FtYjJjLm9ubWljcm9zb2Z0LmNvbSIsInVwbiI6InJib290aF9jYWxsaWJyaXR5LmNvbSNFWFQjQGZhYnJpa2FtYjJjLm9ubWljcm9zb2Z0LmNvbSIsInZlciI6IjEuMCJ9.MPPkvUc0bHuVyf8hr4JZ0hG0mLE2pT7maDR-10e3XR8m6FtrsmQlkgvhnzfao94jPzDzX_CnG_Asfnqv04JeIpvQXBlViO63AlfZaZVllLByeJti5Uat1WepMPz5MRydk6b2o5w_xRfl7QOI-L9Yt8r7-rQX1FMuIPfvvsUity-M-H8s0XInvihxiKEHU_wvz6U017Tgjs4qcrpILM5Ziaxfb7oSxgECl3EDWAoITDy5B-rYCH_o-7mhxHQauUYgH5dUV2MrM8iuaMPoRc3r9Xk38SyfgS1-4taK_bi_AIutyOBX4O3cWbrvGDshQbHBW4BmjctTBT-xUPWboydpuA

我指定我的 java 代码使用以下端点进行令牌验证。

https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1_sign_in

在撰写本文时,这是该端点的 json。

{
  "keys": [
    {"kid":"IdTokenSigningKeyContainer","use":"sig","kty":"RSA","e":"AQAB","n":"tLDZVZ2Eq_DFwNp24yeSq_Ha0MYbYOJs_WXIgVxQGabu5cZ9561OUtYWdB6xXXZLaZxFG02P5U2rC_CT1r0lPfC_KHYrviJ5Y_Ekif7iFV_1omLAiRksQziwA1i-hND32N5kxwEGNmZViVjWMBZ43wbIdWss4IMhrJy1WNQ07Fqp1Ee6o7QM1hTBve7bbkJkUAfjtC7mwIWqZdWoYIWBTZRXvhMgs_Aeb_pnDekosqDoWQ5aMklk3NvaaBBESqlRAJZUUf5WDFoJh7yRELOFF4lWJxtArTEiQPWVTX6PCs0klVPU6SRQqrtc4kKLCp1AC5EJqPYRGiEJpSz2nUhmAQ"}
  ]
}

这是我使用的java代码

package com.example

import org.jose4j.jwk.HttpsJwks
import org.jose4j.jwt.JwtClaims
import org.jose4j.jwt.consumer.InvalidJwtException
import org.jose4j.jwt.consumer.JwtConsumer
import org.jose4j.jwt.consumer.JwtConsumerBuilder
import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver

class AzureB2CPOC7 {

public static talk(){

    String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJiYjJhMmUzYS1jNWU3LTRmMGEtODhlMC04ZTAxZmQzZmMxZjQiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83NzU1MjdmZi05YTM3LTQzMDctOGIzZC1jYzMxMWY1OGQ5MjUvIiwiaWF0IjoxNDU4NDMzMDIzLCJuYmYiOjE0NTg0MzMwMjMsImV4cCI6MTQ1ODQzNjkyMywiYW1yIjpbInB3ZCJdLCJpcGFkZHIiOiI3NC4xMzkuMjEzLjE3NSIsIm5hbWUiOiJib2I1Iiwibm9uY2UiOiJMNlNvekpjeVVEc2lYQ2t0NVQwN1NBPT0iLCJvaWQiOiJjNjc0NDA1Yy05ZGIxLTRmN2EtYTIwMy1jNzZkNDk1Zjk5ZDAiLCJwdWlkIjoiMTAwM0JGRkQ5NkQ0NThCMSIsInN1YiI6InozTGRJOWUtSFlWeXpCSl9sOE9RTndWYnRQM3BnbHBwREo3NjJ2TmEycFkiLCJ0aWQiOiI3NzU1MjdmZi05YTM3LTQzMDctOGIzZC1jYzMxMWY1OGQ5MjUiLCJ1bmlxdWVfbmFtZSI6InJib290aF9jYWxsaWJyaXR5LmNvbSNFWFQjQGZhYnJpa2FtYjJjLm9ubWljcm9zb2Z0LmNvbSIsInVwbiI6InJib290aF9jYWxsaWJyaXR5LmNvbSNFWFQjQGZhYnJpa2FtYjJjLm9ubWljcm9zb2Z0LmNvbSIsInZlciI6IjEuMCJ9.MPPkvUc0bHuVyf8hr4JZ0hG0mLE2pT7maDR-10e3XR8m6FtrsmQlkgvhnzfao94jPzDzX_CnG_Asfnqv04JeIpvQXBlViO63AlfZaZVllLByeJti5Uat1WepMPz5MRydk6b2o5w_xRfl7QOI-L9Yt8r7-rQX1FMuIPfvvsUity-M-H8s0XInvihxiKEHU_wvz6U017Tgjs4qcrpILM5Ziaxfb7oSxgECl3EDWAoITDy5B-rYCH_o-7mhxHQauUYgH5dUV2MrM8iuaMPoRc3r9Xk38SyfgS1-4taK_bi_AIutyOBX4O3cWbrvGDshQbHBW4BmjctTBT-xUPWboydpuA";
    HttpsJwks httpsJkws = new HttpsJwks("https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1_sign_in");
    HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);
    JwtConsumer jwtConsumer = new JwtConsumerBuilder()
            .setRequireExpirationTime() // the JWT must have an expiration time
            .setAllowedClockSkewInSeconds(3600) // allow some leeway in validating time based claims to account for clock skew
            .setRequireSubject() // the JWT must have a subject claim
            .setExpectedIssuer("https://sts.windows.net/775527ff-9a37-4307-8b3d-cc311f58d925/") // whom the JWT needs to have been issued by
            .setExpectedAudience("bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4") // to whom the JWT is intended for
            .setVerificationKeyResolver(httpsJwksKeyResolver)
            .build();

    try
    {
        //  Validate the JWT and process it to the Claims
        JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt);
        System.out.println("JWT validation succeeded! " + jwtClaims);
    }
    catch (InvalidJwtException e)
    {
        // InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
        // Hopefully with meaningful explanations(s) about what went wrong.
        System.out.println("Invalid JWT! " + e);
    }
}
}

起初,我收到此错误消息“无法为带有标头的 JWS 找到合适的验证密钥”。因此,我创建了一个本地 Web 服务器并从 microsoft json 端点复制了 json,但我将“kid”:“IdTokenSigningKeyContainer”替换为“kid”:“MnC_VZcATfM5pOYiJHMba9goEKY”。

该更改修复了“无法为带有标头的 JWS 找到合适的验证密钥”错误消息,但我收到了以下错误,而不是“JWS 签名无效”。

我正在寻找一种 java 解决方案来验证上面列出的 jwt id 令牌的签名。提前致谢。

【问题讨论】:

    标签: java azure jwt adal jose4j


    【解决方案1】:

    尝试将https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/discovery/v2.0/keys 用于 HTTPS JWKS 位置。那里有一个不同的密钥,它有一个与 JWT 中的内容相匹配的 child 和 x5t。

    【讨论】:

      【解决方案2】:

      那个网址:

      https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1_sign_in

      只是为每个 b2c 租户提供的通用端点的示例

      https://login.microsoftonline.com/{您的租户名称}/discovery/v2.0/keys?p={您的登录注册政策}

      ,Azure b2c 令牌本身不提供密钥,而只提供密钥 ID“kid”,但是在自定义端点提供的 json 对象包含编码验证密钥所需的所有组件,您只需要“e”和“n”值

      public class KeyUtilHandler {
      
      // values "n" and "e" from json object at
      // https://login.microsoftonline.com/{your tenant name}/discovery/v2.0/keys?p={your sign in sign up policy}
      
      private String eValue;
      private String nValue;
      
      public String stringPublicKey(){
      
          byte[] modulusBytes = Base64.getUrlDecoder().decode(nValue);
          BigInteger modulusInt = new BigInteger(1, modulusBytes);
      
          byte[] exponentBytes = Base64.getUrlDecoder().decode(eValue);
          BigInteger exponentInt = new BigInteger(1, exponentBytes);
      
          KeyFactory keyFactory;
      
          RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(modulusInt, exponentInt);
      
          String encodedStringKey = null;
      
          {
              try {
                  keyFactory = KeyFactory.getInstance("RSA");
      
                  RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(publicSpec);
      
                  byte [] encodedKey = publicKey.getEncoded();
      
                  encodedStringKey = Base64.getEncoder().encodeToString(encodedKey);
      
              } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
                  e.printStackTrace();
              }
          }
      
          return String.format("-----BEGIN PUBLIC KEY-----%s-----END PUBLIC KEY-----"
                  , encodedStringKey);
      }
      

      【讨论】:

        猜你喜欢
        • 2016-07-13
        • 1970-01-01
        • 2021-11-16
        • 2021-08-21
        • 2018-10-02
        • 2018-12-25
        • 2022-01-18
        • 2020-07-08
        • 2019-11-01
        相关资源
        最近更新 更多