取得可呼叫 Web API 的行動應用程式權杖
在應用程式可以呼叫受保護的 Web API 之前,其需要存取權杖。 本文將逐步引導您使用 Microsoft 驗證程式庫 (MSAL) 來取得權杖。
定義範圍
當您要求權杖時,請定義範圍。 範圍會決定您的應用程式可以存取的資料。
定義範圍最簡單的方式,就是將所需的 Web API App ID URI
與範圍 .default
合併。 此定義會告知 Microsoft 身分識別平台您的應用程式需要在入口網站中設定的所有範圍。
Android
String[] SCOPES = {"https://graph.microsoft.com/.default"};
iOS
let scopes = ["https://graph.microsoft.com/.default"]
取得權杖
透過 MSAL 取得權杖
MSAL 可讓應用程式以無訊息方式和以互動方式取得權杖。 當您呼叫 AcquireTokenSilent()
或 AcquireTokenInteractive()
時,MSAL 會針對要求的範圍傳回存取權杖。 正確的模式是發出無訊息要求,然後切換回互動式要求。
Android
String[] SCOPES = {"https://graph.microsoft.com/.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) {
// One account found, attempt silent sign-in.
sampleApp.acquireTokenSilentAsync(SCOPES, accounts.get(0), getAuthSilentCallback());
} else if (accounts.isEmpty()) {
// No accounts found. Interactively request a token.
sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback());
} else {
// Multiple accounts found. Handle according to your app logic.
// You may need to prompt the user to select an account.
}
}
});
[...]
// No accounts found. Interactively request a token.
// TODO: Create an interactive callback to catch successful or failed requests.
sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback());
iOS
請先嘗試以無訊息方式取得權杖:
NSArray *scopes = @[@"https://graph.microsoft.com/.default"];
NSString *accountIdentifier = @"my.account.id";
MSALAccount *account = [application accountForIdentifier:accountIdentifier error:nil];
MSALSilentTokenParameters *silentParams = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account];
[application acquireTokenSilentWithParameters:silentParams completionBlock:^(MSALResult *result, NSError *error) {
if (!error)
{
// You'll want to get the account identifier to retrieve and reuse the account
// for later acquireToken calls
NSString *accountIdentifier = result.account.identifier;
// Access token to call the web API
NSString *accessToken = result.accessToken;
}
// Check the error
if (error && [error.domain isEqual:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
{
// Interactive auth will be required, call acquireTokenWithParameters:error:
return;
}
}];
let scopes = ["https://graph.microsoft.com/.default"]
let accountIdentifier = "my.account.id"
guard let account = try? application.account(forIdentifier: accountIdentifier) else { return }
let silentParameters = MSALSilentTokenParameters(scopes: scopes, account: account)
application.acquireTokenSilent(with: silentParameters) { (result, error) in
guard let authResult = result, error == nil else {
let nsError = error! as NSError
if (nsError.domain == MSALErrorDomain &&
nsError.code == MSALError.interactionRequired.rawValue) {
// Interactive auth will be required, call acquireToken()
return
}
return
}
// You'll want to get the account identifier to retrieve and reuse the account
// for later acquireToken calls
let accountIdentifier = authResult.account.identifier
// Access token to call the web API
let accessToken = authResult.accessToken
}
如果 MSAL 傳回 MSALErrorInteractionRequired
,則嘗試以互動方式取得權杖:
UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively
MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController];
MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters];
[application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) {
if (!error)
{
// You'll want to get the account identifier to retrieve and reuse the account
// for later acquireToken calls
NSString *accountIdentifier = result.account.identifier;
NSString *accessToken = result.accessToken;
}
}];
let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively
let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters)
application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in
guard let authResult = result, error == nil else {
print(error!.localizedDescription)
return
}
// Get access token from result
let accessToken = authResult.accessToken
})
適用於 iOS 和 macOS 的 MSAL 支援各種修飾元,以互動或無訊息方式取得權杖:
MSAL.NET 中的強制參數
AcquireTokenInteractive
只有一個強制參數:scopes
。 scopes
參數會列舉字串,以定義需要權杖的範圍。 如果權杖是用於 Microsoft Graph,您就可以在每個 Microsoft Graph API 的 API 參考中找到所需的範圍。 在參考中,移至 [權限] 區段。
例如,若要列出使用者的連絡人,請使用「User.Read」、「Contacts.Read」等範圍。 如需詳細資訊,請參閱 Microsoft Graph 權限參考。
在 Android 上,您可以在使用 PublicClientApplicationBuilder
建立應用程式時指定父活動。 如果您在該時間未指定父活動,稍後您可以使用 .WithParentActivityOrWindow
來加以指定,如下一節所示。 如果您指定父活動,則在互動之後,權杖會回到該父活動。 如果您未指定,則 .ExecuteAsync()
呼叫會擲回例外狀況。
MSAL.NET 中的特定選擇性參數
下列各節說明 MSAL.NET 中的選擇性參數。
WithPrompt
WithPrompt()
參數是透過指定提示,以控制使用者的互動性。
類別會定義下列常數:
SelectAccount
強制安全性權杖服務 (STS),以顯示 [帳戶選取] 對話方塊。 此對話方塊包含使用者有工作階段的帳戶。 當您想要讓使用者在不同的身分識別之間進行選擇時,可以使用此選項。 此選項會驅動 MSAL,以將prompt=select_account
傳送至識別提供者。SelectAccount
常數是預設值,其可以有效地根據可用資訊來提供最佳體驗。 可用的資訊可能包括帳戶、使用者的工作階段是否存在等等。 除非您有充分的理由,否則請勿變更此預設值。即使之前已授與同意,
Consent
也可讓您提示使用者進行同意。 在此情況下,MSAL 會將prompt=consent
傳送給識別提供者。您可能會想要在安全性導向的應用程式中使用
Consent
常數,其中組織治理會要求使用者在每次使用應用程式時都看到同意對話方塊。即使不需要提示,
ForceLogin
也可讓服務提示使用者輸入認證。如果權杖取得失敗,而您想要讓使用者再次登入,此選項會很有用。 在此情況下,MSAL 會將
prompt=login
傳送給識別提供者。 您可能會想要在安全性導向的應用程式中使用此選項,其中組織治理會要求使用者在每次存取應用程式的特定部分時登入。Never
僅適用於 .NET 4.5 和 Windows 執行階段 (WinRT)。 這個常數不會提示使用者,但其會嘗試使用儲存在隱藏內嵌 Web 檢視中的 Cookie。 如需詳細資訊,請參閱使用網頁瀏覽器搭配 MSAL.NET。如果此選項失敗,則
AcquireTokenInteractive
會擲回例外狀況,以通知您需要 UI 互動。 然後使用另一個Prompt
參數。NoPrompt
不會將任何提示傳送給識別提供者。此選項僅適用於 Azure Active Directory B2C 編輯設定檔原則。 如需詳細資訊,請參閱 B2C 詳細資料。
WithExtraScopeToConsent
在您希望使用者對數個資源提供預先同意的進階情節中使用 WithExtraScopeToConsent
修飾元。 如果您不想要使用增量同意 (通常與 MSAL.NET 或 Microsoft 身分識別平台搭配使用),您可以使用此修飾元。 如需詳細資訊,請參閱將數個資源進行預先同意。
這裡提供程式碼範例:
var result = await app.AcquireTokenInteractive(scopesForCustomerApi)
.WithExtraScopeToConsent(scopesForVendorApi)
.ExecuteAsync();
其他選擇性參數
若要瞭解 AcquireTokenInteractive
的其他選擇性參數,請參閱 AcquireTokenInteractiveParameterBuilder 的參考文件。
透過通訊協定取得權杖
我們不建議直接使用通訊協定來取得權杖。 這樣一來,應用程式將不會支援涉及單一登入 (SSO)、裝置管理和條件式存取的部分案例。
當您使用通訊協定來取得行動應用程式的權杖時,請提出兩個要求:
- 取得授權碼。
- 交換權杖的程式碼。
取得授權碼
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=<CLIENT_ID>
&response_type=code
&redirect_uri=<ENCODED_REDIRECT_URI>
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2F.default
&state=12345
取得存取權並重新整理權杖
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=<CLIENT_ID>
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
&redirect_uri=<ENCODED_REDIRECT_URI>
&grant_type=authorization_code
下一步
若要深入了解,請建置 React 單頁應用程式 (SPA),以在下列多部分教學課程系列中登入使用者。