如何在多线程应用程序中管理 ADAL 身份验证令牌的检索

How to manage retrieval of ADAL auth token in a mulithreaded application

我有大量基于多线程 java 的应用程序,它需要在 Microsoft 云上调用基于 REST 的端点 运行,并使用 "Azure ADAL AcquireToken" 检索的 header 中的授权令牌.我正在使用 "AzureAD/azure-activedirectory-library-for-java"(下面的代码示例)。我的问题是 -

  1. 我是否需要使用 acquireToken 调用来检索令牌 我要进行的每个 REST 调用的方法?如果是,那么 我相信我将通过最近一次通话获得的令牌可能会改变, 如果我已经提出请求,那么在那种情况下是请求 之前检索到的令牌将失败或 Azure ADAL 将 仍然要兑现所有以前生成的令牌吗?
  2. 如果之前检索到的令牌预计不会被 Azure 接受 ADAL 那么我有哪些选项可以一次管理单个令牌 然后确保一次只有一个令牌被所有 要求?我需要实现某种单线程缓存吗 检索令牌,维护该令牌直到它过期,做一个 如果过期则调用获取新令牌并使我的所有多线程 请求通过这个单线程缓存来获取最新的 令牌?对此有任何建议。如果是这样的话,那么它似乎 就像大容量多线程多 jvm 中的巨大瓶颈 就可扩展性而言的应用程序。

下面是我的代码。当我从 main 方法内的循环调用 acquireToken 方法时,我在 10 次调用中主要获得了 3 种不同类型的令牌,所有 3 种不同的令牌似乎都有效,但不确定在多线程应用程序中是否应该如何调用它。

package com.mycompany.msft.auth;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;

public class ApplicationAuthExample {
    private final static String AUTHORIZATION_ENDPOINT = "https://login.microsoftonline.com/";
    private final static String ARM_ENDPOINT = "https://myendpoint";


    private static String credential = "my credential";
    private static String clientId = "my client id";
    private static String tenantId = "my tenant id";

    private static String url = AUTHORIZATION_ENDPOINT + tenantId ;

    AuthenticationContext context = null;
    AuthenticationResult result = null;
    ExecutorService service = null;

    public  AuthenticationResult getAuthToken() {
        try {
            service = Executors.newFixedThreadPool(1);


            context = new AuthenticationContext(url, false, service);

            Future<AuthenticationResult> future = null;


                ClientCredential cred = new ClientCredential(clientId, credential);
                future = context.acquireToken(ARM_ENDPOINT, cred, null);


            result = future.get();
        } catch (Exception ex) {
            System.out.println("Exception occurred:");
            ex.printStackTrace();
            System.exit(1);
        } finally {
            service.shutdown();
        }
        return result;
    }

    public static void main(String[] args) throws Exception {

        ApplicationAuthExample auth = new ApplicationAuthExample();

        for (int i =0 ; i< 10 ; i++) {
            AuthenticationResult result = auth.getAuthToken();
            // use adal to Authenticate

            System.out.println (i+ " Authorization" + "Bearer " + result.getAccessToken());
            System.out.println (i + " getExpiresOn" + result.getExpiresOn());

            //This token comes different in different calls. Which one should I use and which one not. 
            System.out.println (i+ " getExpiresOn" + result.getRefreshToken());


            System.out.println (i+" getExpiresOn" + result.getUserInfo());
            }

    }
}

根据我的经验,我认为问题的关键是令牌的过期时间。令牌过期后,您可以随意使用。可以参考https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-tokens/Claims in id_tokens部分知道token领取时间包括Issued At, Expriation Time & `Not Before.

因此您需要使用adal4j获取令牌并在前一个令牌过期时请求刷新令牌。

The lifetime of a default security token for a claims-based authentication deployment using AD FS 2.0 is 60 minutes.

如果想增加Azure AD的token过期时间,可以尝试参考文档https://technet.microsoft.com/en-us/library/gg188586.aspx配置relying party token生命周期