验证 Azure AD JWT 访问令牌时出错

Error validating Azure AD JWT access token

提问人:vcima 提问时间:3/31/2020 最后编辑:vcima 更新时间:4/7/2020 访问量:2776

问:

我有一个使用 Msal 库获取的 Azure AD JWT 令牌,但当我尝试验证此令牌时,会出现以下问题:

客户端:SharePoint Web 部件

const config = {
 auth: {
     clientId: "xxxxx",
     authority: "https://login.microsoftonline.com/yyyyyy"
 }
};

const myMSALObj = new UserAgentApplication(config);

let accessTokenRequest = {
 scopes: ["user.read"],
 loginHint: this.context.pageContext.user.loginName,
 extraQueryParameters: {domain_hint: 'organizations'}
}

myMSALObj.acquireTokenSilent(accessTokenRequest).then(
function(accessTokenResponse) { 
// Acquire token silent success 
let accessToken = accessTokenResponse.accessToken;

另一方面,我有一个服务器应用程序(Java),用于验证访问令牌

验证者:

<dependency>
  <groupId>com.microsoft.azure</groupId>
  <artifactId>azure-storage</artifactId>
  <version>8.6.2</version>
</dependency>

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>jwks-rsa</artifactId>
  <version>0.11.0</version>
</dependency>

法典

 String token="<your AD token>";
    DecodedJWT jwt = JWT.decode(token);
    System.out.println(jwt.getKeyId());

    JwkProvider provider = null;
    Jwk jwk =null;
    Algorithm algorithm=null;

    try {
       provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/common/discovery/keys"));
      jwk = provider.get(jwt.getKeyId());
      algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
      algorithm.verify(jwt);// if the token signature is invalid, the 
    method will throw SignatureVerificationException
     } catch (MalformedURLException e) {
         e.printStackTrace();
     } catch (JwkException e) {
        e.printStackTrace();
     }catch(SignatureVerificationException e){
       System.out.println(e.getMessage());
     }

我的问题是,当我尝试验证此令牌时,我收到了以下错误:使用算法验证时令牌的签名无效:SHA256withRSA

我被困在这个,如果令牌是正确的,为什么我有这个错误?

问候

Azure Azure-active-Directory

评论

0赞 Toby Artisan 3/31/2020
两个问题:1.你使用的是 MSAL.js 吗?2. 是否在 MSAL 获取令牌后手动验证令牌?MSAL 应该会为你验证它,因此你不必自己进行任何显式验证。
0赞 vcima 3/31/2020
嗨,@Toby,感谢您的回复。是的,我正在使用 MSAL.js 在客户端中获取令牌。之后,我使用此令牌调用外部 API。当我尝试验证令牌时,出现问题并失败。我已将我的验证器添加到代码中
0赞 Toby Artisan 3/31/2020
您是否能够获得 JWT 令牌的副本并在 jwt.io 对其进行解码?如果可以,则可以通过查看 jwt.io 处的 HEADER 区域来验证令牌的签名是否已使用 RSA256 算法签名。如果它不使用该算法,那么这就是问题所在。
0赞 Toby Artisan 3/31/2020
如果令牌是使用 RSA256 算法签名的,那么你是否知道 Azure AD 是否使用默认设置来颁发令牌,或者是否使用自定义签名算法和/或自定义证书设置了自定义配置?如果您使用的是自定义证书,请确保有关该证书的以下内容: 1.未过期。2. 它是由公共机构颁发的。如果它是由私人机构颁发的,那么你需要自定义代码来信任该颁发者。
0赞 vcima 3/31/2020
嗨,@Toby,是的“alg”:“RS256”,对吗?

答:

2赞 Tony Ju 4/1/2020 #1

我注意到范围是,这意味着令牌用于 Microsoft 图形 API。user.read

请注意:

如果你是获取 Graph 令牌的客户端,假设它是 你永远不应该看的加密字符串 - 有时它会。 我们为 Graph 使用一种特殊的令牌格式,他们知道如何验证 - 如果访问令牌不适合您,则不应查看它们。

可以使用此访问令牌直接调用 Microsoft 图形 API,如果令牌错误,您将收到来自 Microsoft API 服务器的响应。

参考:

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609#issuecomment-529537264

评论

0赞 vcima 4/7/2020
嗨,@Tony Ju,你是对的。无法使用 user.read 通过此方法验证此令牌,因为结果是图形令牌。
2赞 vcima 4/7/2020 #2

最后,它适用于这样的东西。

  1. 若要获取令牌(在 Web 部件中使用 adal),请执行以下操作:

        // Obtaining token provider
        let tp = await this.context.aadTokenProviderFactory.getTokenProvider();
        let config = tp["_defaultConfiguration"];
        let aadInstanceUrl = config.aadInstanceUrl[length - 1] === "/" ? config.aadInstanceUrl : config.aadInstanceUrl + "/";
    
        // Config context
        let ctx = new AuthenticationContext({
            tenant: tenantId,
            clientId: clientId,
            instance: aadInstanceUrl,
            redirectUri: config.redirectUri,
            extraQueryParameter: "login_hint=" + encodeURIComponent(loginName),
            loadFrameTimeout: 60000
        });
    
        // Check user
        let cu = ctx.getCachedUser();
    
        console.log("USER", cu, loginName, ctx);
        if (cu && cu.userName.toLowerCase() !== loginName.toLowerCase()) {
            console.log("Clean user cache");
            ctx.clearCache();
        }
    
        // Login process
        console.log("Login process");
    
        // Obtaining Azure AD Token
        let azureADToken = this.acquireToken(ctx, clientId);
    
  2. 要验证令牌,请执行以下操作:

    String token = "XXXXXX";
    
    DecodedJWT jwt = JWT.decode(token);
    System.out.println(jwt.getKeyId());
    
    JwkProvider provider = null;
    Jwk jwk = null;
    Algorithm algorithm = null;
    
    try {
        provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/common/discovery/keys"));
        jwk = provider.get(jwt.getKeyId());
        algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
        algorithm.verify(jwt);// if the token signature is invalid, the method will throw
        // SignatureVerificationException
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (JwkException e) {
        e.printStackTrace();
    } catch (SignatureVerificationException e) {
    
        System.out.println(e.getMessage());
    
    }
    
    System.out.println("works!");
    

使用此依赖项:

  <dependencies>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.1</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.1</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
            <version>0.11.1</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.10</version>
            <type>bundle</type>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
            <type>bundle</type>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.10</version>
            <type>bundle</type>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
        <!-- JUNIT -->
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-storage</artifactId>
            <version>8.6.2</version>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>jwks-rsa</artifactId>
            <version>0.11.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.2</version>
        </dependency>

    </dependencies>

评论

0赞 Tony Ju 4/20/2020
你可以接受它作为答案,它可以被其他人看到。