呼叫 Web API 的傳統型應用程式:使用裝置代碼流程取得權杖
如果您要撰寫的命令列工具沒有 Web 控制項,且您無法或不想要使用先前的流程,請使用裝置代碼流程。
裝置代碼流程
使用 Microsoft Entra ID 的互動式驗證需要網頁瀏覽器。 如需詳細資訊,請參閱網頁瀏覽器的使用方式。 若要在不提供網頁瀏覽器的裝置或作業系統上驗證使用者,裝置程式碼流程可讓使用者使用另一部裝置 (例如電腦或行動電話) 以互動方式登入。 使用裝置代碼流程,應用程式就能透過針對這些裝置或作業系統所設計的雙步驟程序來取得權杖。 這類應用程式的範例,是在 iOT 或命令列工具 (CLI) 上執行的應用程式。 其概念如下:
每當需要使用者驗證時,應用程式會為使用者提供程式碼。 系統會要求使用者使用另一部裝置 (例如網際網路連線的智慧型手機) 來移至 URL,例如
https://microsoft.com/devicelogin
。 接著,系統會提示使用者輸入程式碼。 如此一來,網頁會引導使用者完成一般的驗證體驗,其中包括同意提示和多重要素驗證 (如有需要)。成功驗證之後,命令列應用程式會透過後端通道接收所需的權杖,並使用這些權杖來執行所需的 Web API 呼叫。
請善加利用
IPublicClientApplication
包含名為 AcquireTokenWithDeviceCode
的方法。
AcquireTokenWithDeviceCode(IEnumerable<string> scopes,
Func<DeviceCodeResult, Task> deviceCodeResultCallback)
此方法採用以下參數:
- 用於要求存取權杖的
scopes
。 - 接收
DeviceCodeResult
的回撥。
下列範例程式碼會呈現最新案例的概要,並說明您可以取得的例外狀況種類及其緩解措施。 如需完整功能程式碼範例,請參閱 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。