AzureAD for Android抛出ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED

时间:2016-01-05 14:37:48

标签: android office365 adal azure-active-directory

我有一个应用程序,其中用户使用AzureAD library for Android在Office365中进行身份验证。

它运行良好,用户可以验证并使用该应用程序。不幸的是,经过一段时间后,他们以 AuthenticationException 作为错误代码开始 ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED

我检查了AzurelAD的source code。解决此问题的唯一地方是acquireTokenAfterValidation()方法:

private AuthenticationResult acquireTokenAfterValidation(CallbackHandler callbackHandle,
        final IWindowComponent activity, final boolean useDialog,
        final AuthenticationRequest request) {
    Logger.v(TAG, "Token request started");

    // BROKER flow intercepts here
    // cache and refresh call happens through the authenticator service
    if (mBrokerProxy.canSwitchToBroker()
            && mBrokerProxy.verifyUser(request.getLoginHint(),
                    request.getUserId())) {
        .......
        Logger.v(TAG, "Token is not returned from backgroud call");
        if (!request.isSilent() && callbackHandle.callback != null && activity != null) {
            ....
        } else {
            // User does not want to launch activity
            String msg = "Prompt is not allowed and failed to get token:";
            Logger.e(TAG, msg, "", ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED);
            callbackHandle.onError(new AuthenticationException(
                    ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED, msg));
        }

        // It will start activity if callback is provided. Return null here.
        return null;
    } else {
        return localFlow(callbackHandle, activity, useDialog, request);
    }
}

我的源代码:

authenticator.getAccessTokenSilentSync(getMailService());

public class Authenticator {
    ..............
    public String getAccessTokenSilentSync(ServiceInfo serviceInfo) {
        throwIfNotInitialized();
        return getAuthenticationResultSilentSync(serviceInfo).getAccessToken();
    }

    private AuthenticationResult getAuthenticationResultSilentSync(ServiceInfo serviceInfo) {
        try {
            return authenticationContext.acquireTokenSilentSync(
                    serviceInfo.ServiceResourceId,
                    Client.ID,
                    userIdentity.getAdUserId());
        } catch (AuthenticationException ex) {
            // HERE THE EXCEPTION IS HANDLED.
        }
    }
    ..............
} 

Stacktrace我得到了:

    <package name>.data_access.error_handler.AuthenticationExceptionWithServiceInfo: Refresh token is failed and prompt is not allowed
    at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1294)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
    at com.microsoft.aad.adal.AuthenticationContext.refreshToken(AuthenticationContext.java:1609)
    at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1261)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
    at com.microsoft.aad.adal.AuthenticationContext.refreshToken(AuthenticationContext.java:1609)
    at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1261)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
    at com.microsoft.aad.adal.AuthenticationContext.access$600(AuthenticationContext.java:58)
    at com.microsoft.aad.adal.AuthenticationContext$4.call(AuthenticationContext.java:1072)
    at com.microsoft.aad.adal.AuthenticationContext$4.call(AuthenticationContext.java:1067)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)

AzureAD库的版本我使用:1.1.7(为了防止归咎于旧版本 - 我已经检查了从1.1.7到1.1.11的更改列表并且没有找到任何内容与问题有关)

问题:现在,我将此错误视为通过用户登录屏幕的信号。在我看来,它会导致用户体验不佳。它经常发生 非常 并影响许多用户的事实使其更糟糕。

问题:我能做些什么来避免这种情况AuthenticationException或以某种方式解决它(即避免用户再次输入凭据)。

2 个答案:

答案 0 :(得分:2)

您是否确认AuthenticationContext.acquireTokenSilentSync()确实是您想要调用的方法?

文档表明此方法将明确不显示提示。来自文档:

This is sync function. It will first look at the cache and automatically checks for the token expiration. Additionally, if no suitable access token is found in the cache, but refresh token is available, the function will use the refresh token automatically. This method will not show UI for the user. If prompt is needed, the method will return an exception.

根据此AAD book,您发布的刷新令牌应持续两周。刷新令牌到期后,用户需要重新进行身份验证。你能用Fiddler或Charles检查净流量并检查令牌的到期吗?如果您可以验证令牌在到期之前未能刷新,则可能表示AD库中存在错误。

澄清AuthenticationContext方法的不同之处 - 有两类方法:“无声”方法(在需要重新认证的情况下不会向用户显示对话框)和非静默方法。在需要用户重新认证(或同意)的情况下,非静默方法将启动包含AAD登录的新活动。此时,重新启动身份验证流程。

此外,如果您更改了应用程序在Azure中的注册,例如添加新的权限范围,则您的用户将需要重新授予应用程序同意才能继续处理其数据。

答案 1 :(得分:1)

这是因为您需要刷新令牌并在代码中实现此功能,以便每次访问令牌过期时用户都不会提示登录。请在此处查看如何实施刷新令牌:

https://msdn.microsoft.com/en-us/library/azure/dn645538.aspx

希望这有帮助。