android - 在 Android 上使用 MSAL 获取访问 token 来调用受 Azure AD 保护的 API 会出现 MsalDeclinedScopeException

标签 android azure kotlin azure-active-directory azure-ad-msal

我正在使用 MSAL 以单帐户模式将用户登录到 Android 应用程序。这有效。我希望能够使用收到的访问 token 来调用受 Azure AD 保护的 API 终结点。我已注册客户端应用程序和 API,并已授予从 API 到客户端应用程序所需范围的访问权限。

这是我的 build.gradle 中的库引用

implementation "com.microsoft.identity.client:msal:2.0.8"

我们在 Azure 门户中使用应用程序注册体验,并将 v2.0 授权端点与 Postman 的 OAuth2 token acquisition 结合使用。功能,效果很好。这是我的设置

Grant Type           : Authorization Code (With PKCE)
Callback URL         : "http://localhost"
Authorization URL    : "https://login.microsoftonline.com/{{Tenant}}/oauth2/v2.0/authorize"
Token URL            : "https://login.microsoftonline.com/{{Tenant}}/oauth2/v2.0/token"
Client ID & Client Secret from portal
Code Challenge Method: SHA-256
Scope                : From API Registration

但是,MSAL Android 的 token 没有范围或受众。身份验证失败,日志如下:

Authentication failed: com.microsoft.identity.client.exception.MsalDeclinedScopeException: Some or all requested scopes have been declined by the Server

此行为似乎与使用旧授权端点时发生的情况相当一致。
无论如何,是否有针对此问题的修复/解决方法,或者我可以采取其他措施来使其正常工作?

编辑
以下是 API 应用程序注册中公开 API Blade 的屏幕截图
Expose API from API registration

这是我用来登录用户的 Kotlin 代码

var SCOPES = arrayOf("api://<api-app-id>/<scope-name>","api://<api-app-id>/scope-name>")
PublicClientApplication.createSingleAccountPublicClientApplication(
  applicationContext,
  R.raw.auth_config_single_account, object : ISingleAccountApplicationCreatedListener {
  override fun onCreated(application: ISingleAccountPublicClientApplication) {
    mSingleAccountApp = application
    loadAccount()  //processes the logged in account
  }
  override fun onError(exception: MsalException) {
  }
})
loginButton.setOnClickListener(View.OnClickListener {
    if (mSingleAccountApp == null) {
        return@OnClickListener
    }
    getAuthInteractiveCallback()?.let { it1 ->
        mSingleAccountApp!!.signIn(
            this@MainActivity,
            null,
            SCOPES,
            it1
        )
    }
})

最佳答案

不确定您提到的自定义范围。您需要使用 api://<client-id>/xxx 更改范围像这样。

enter image description here

请尝试以下代码。

通过 MSAL 获取 token :

String[] SCOPES = {"api://<client-id>/.default"};
PublicClientApplication sampleApp = new PublicClientApplication(
                    this.getApplicationContext(),
                    R.raw.auth_config);

// Check if there are any accounts we can sign in silently.
// Result is in the silent callback (success or error).
sampleApp.getAccounts(new PublicClientApplication.AccountsLoadedCallback() {
    @Override
    public void onAccountsLoaded(final List<IAccount> accounts) {

        if (accounts.isEmpty() && accounts.size() == 1) {
            // TODO: Create a silent callback to catch successful or failed request.
            sampleApp.acquireTokenSilentAsync(SCOPES, accounts.get(0), getAuthSilentCallback());
        } else {
            /* No accounts or > 1 account. */
        }
    }
});

[...]

// No accounts found. Interactively request a token.
// TODO: Create an interactive callback to catch successful or failed requests.
sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback());

使用访问 token 调用 API:

    RequestQueue queue = Volley.newRequestQueue(this);
    JSONObject parameters = new JSONObject();

    try {
        parameters.put("key", "value");
    } catch (Exception e) {
        // Error when constructing.
    }
    JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, MSGRAPH_URL,
            parameters,new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            // Successfully called Graph. Process data and send to UI.
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            // Error.
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> headers = new HashMap<>();
            
            // Put access token in HTTP request.
            headers.put("Authorization", "Bearer " + accessToken);
            return headers;
        }
    };

    request.setRetryPolicy(new DefaultRetryPolicy(
            3000,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    queue.add(request);

关于android - 在 Android 上使用 MSAL 获取访问 token 来调用受 Azure AD 保护的 API 会出现 MsalDeclinedScopeException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67160840/

相关文章:

android - Scrollview 内部 SignatureView 不工作

Android AlarmManager - RTC_WAKEUP 与 ELAPSED_REALTIME_WAKEUP

android - 在自定义键盘中添加下一个按钮

c# - 使用 Windows Azure 服务总线扩展 SignalR

c# - 访问 Azure 辅助角色中托管的 ApiController 中的客户端证书

android - 使用 c2dm 一次发送多个推送

Python Azure 事件中心使用事件属性

android - 如何在终端中运行 Android Studio 代码检查

kotlin - Kotlin-可变子类的扩展属性 setter

android - 暂停 kotlin 协程异步子函数