呼叫 Web API 的桌面應用程式:使用裝置程式代碼流程取得令牌

如果您要撰寫的命令行工具沒有 Web 控制項,而且您無法或不想使用先前的流程,請使用裝置程式碼流程。

裝置代碼流程

使用 Microsoft Entra ID 進行互動式驗證需要網頁瀏覽器。 如需詳細資訊,請參閱 網頁瀏覽器的使用方式。 若要在未提供網頁瀏覽器的裝置或操作系統上驗證使用者,裝置程式代碼流程可讓使用者使用另一部裝置,例如計算機或行動電話以互動方式登入。 透過使用裝置程式代碼流程,應用程式會透過針對這些裝置或操作系統設計的雙步驟程式來取得令牌。 這類應用程式的範例是在iOT或命令行工具 (CLI) 上執行的應用程式。 其概念是:

  1. 每當需要使用者驗證時,應用程式就會為使用者提供程式碼。 使用者被要求使用另一個裝置,例如因特網連線的智能手機,以移至 URL,例如 https://microsoft.com/devicelogin。 然後,系統會提示使用者輸入代碼。 如此一來,網頁會引導使用者完成一般驗證體驗,包括視需要同意提示和多重要素驗證。

  2. 成功驗證後,命令行應用程式會透過後端通道接收所需的令牌,並使用它們來執行所需的 Web API 呼叫。

使用它

IPublicClientApplication包含名為 AcquireTokenWithDeviceCode的方法。

 AcquireTokenWithDeviceCode(IEnumerable<string> scopes,
                            Func<DeviceCodeResult, Task> deviceCodeResultCallback)

這個方法接受做為參數:

下列範例程式代碼會呈現目前大部分案例的摘要,並說明您可以取得的例外狀況種類及其風險降低。 如需功能完整的程式代碼範例,請參閱 GitHub 上的 active-directory-dotnetcore-devicecodeflow-v2

private const string ClientId = "<client_guid>";
private const string Authority = "https://login.microsoftonline.com/contoso.com";
private readonly string[] scopes = new string[] { "user.read" };

static async Task<AuthenticationResult> GetATokenForGraph()
{
    IPublicClientApplication pca = PublicClientApplicationBuilder
            .Create(ClientId)
            .WithAuthority(Authority)
            .WithDefaultRedirectUri()
            .Build();

    var accounts = await pca.GetAccountsAsync();

    // All AcquireToken* methods store the tokens in the cache, so check the cache first
    try
    {
        return await pca.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
            .ExecuteAsync();
    }
    catch (MsalUiRequiredException ex)
    {
        // No token found in the cache or Azure AD insists that a form interactive auth is required (e.g. the tenant admin turned on MFA)
        // If you want to provide a more complex user experience, check out ex.Classification

        return await AcquireByDeviceCodeAsync(pca);
    }
}

private static async Task<AuthenticationResult> AcquireByDeviceCodeAsync(IPublicClientApplication pca)
{
    try
    {
        var result = await pca.AcquireTokenWithDeviceCode(scopes,
            deviceCodeResult =>
            {
                    // This will print the message on the console which tells the user where to go sign-in using
                    // a separate browser and the code to enter once they sign in.
                    // The AcquireTokenWithDeviceCode() method will poll the server after firing this
                    // device code callback to look for the successful login of the user via that browser.
                    // This background polling (whose interval and timeout data is also provided as fields in the
                    // deviceCodeCallback class) will occur until:
                    // * The user has successfully logged in via browser and entered the proper code
                    // * The timeout specified by the server for the lifetime of this code (typically ~15 minutes) has been reached
                    // * The developing application calls the Cancel() method on a CancellationToken sent into the method.
                    //   If this occurs, an OperationCanceledException will be thrown (see catch below for more details).
                    Console.WriteLine(deviceCodeResult.Message);
                return Task.FromResult(0);
            }).ExecuteAsync();

        Console.WriteLine(result.Account.Username);
        return result;
    }

    // TODO: handle or throw all these exceptions depending on your app
    catch (MsalServiceException ex)
    {
        // Kind of errors you could have (in ex.Message)

        // AADSTS50059: No tenant-identifying information found in either the request or implied by any provided credentials.
        // Mitigation: as explained in the message from Azure AD, the authoriy needs to be tenanted. you have probably created
        // your public client application with the following authorities:
        // https://login.microsoftonline.com/common or https://login.microsoftonline.com/organizations

        // AADSTS90133: Device Code flow is not supported under /common or /consumers endpoint.
        // Mitigation: as explained in the message from Azure AD, the authority needs to be tenanted

        // AADSTS90002: Tenant <tenantId or domain you used in the authority> not found. This may happen if there are
        // no active subscriptions for the tenant. Check with your subscription administrator.
        // Mitigation: if you have an active subscription for the tenant this might be that you have a typo in the
        // tenantId (GUID) or tenant domain name.
    }
    catch (OperationCanceledException ex)
    {
        // If you use a CancellationToken, and call the Cancel() method on it, then this *may* be triggered
        // to indicate that the operation was cancelled.
        // See https://learn.microsoft.com/dotnet/standard/threading/cancellation-in-managed-threads
        // for more detailed information on how C# supports cancellation in managed threads.
    }
    catch (MsalClientException ex)
    {
        // Possible cause - verification code expired before contacting the server
        // This exception will occur if the user does not manage to sign-in before a time out (15 mins) and the
        // call to `AcquireTokenWithDeviceCode` is not cancelled in between
    }
}

下一步

請移至此案例中的下一篇文章, 從傳統型應用程式呼叫Web API。