Karena risiko dan kebijakan dievaluasi secara real time, beberapa masa pakai token API sumber daya dapat meningkat hingga 28 jam. Token berumur panjang ini secara proaktif disegarkan oleh Microsoft Authentication Library (MSAL), meningkatkan ketahanan aplikasi Anda.
Untuk menggunakan CAE, aplikasi Anda dan API sumber daya yang diaksesnya harus diaktifkan CAE. Jika API sumber daya mengimplementasikan CAE dan aplikasi Anda menyatakan dapat menangani CAE, aplikasi Anda menerima token CAE untuk sumber daya tersebut. Untuk alasan ini, jika Anda menyatakan aplikasi Anda siap CAE, aplikasi Anda harus menangani tantangan klaim CAE untuk semua API sumber daya yang menerima token akses Microsoft Identity.
Namun, menyiapkan kode Anda untuk mendukung sumber daya yang didukung CAE tidak membatasi kemampuannya untuk bekerja dengan API yang tidak mendukung CAE. Jika aplikasi Anda tidak menangani respons CAE dengan benar, aplikasi mungkin berulang kali mencoba kembali panggilan API menggunakan token yang secara teknis valid tetapi dicabut karena CAE.
Mulailah dengan menambahkan kode untuk menangani respons dari API sumber daya yang menolak panggilan karena CAE. Dengan CAE, API mengembalikan status 401 dan WWW-Authenticate
header saat token akses dicabut atau API mendeteksi perubahan alamat IP yang digunakan. Header WWW-Authenticate
berisi Tantangan Klaim yang dapat digunakan aplikasi untuk memperoleh token akses baru.
Ketika kondisi ini terpenuhi, aplikasi dapat mengekstrak dan mendekode tantangan klaim menggunakan kelas MSAL.NETWwwAuthenticateParameters
.
if (APIresponse.IsSuccessStatusCode)
{
// ...
}
else
{
if (APIresponse.StatusCode == System.Net.HttpStatusCode.Unauthorized
&& APIresponse.Headers.WwwAuthenticate.Any())
{
string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(APIresponse.Headers);
Aplikasi Anda kemudian menggunakan tantangan klaim untuk memperoleh token akses baru untuk sumber daya.
try
{
authResult = await _clientApp.AcquireTokenSilent(scopes, firstAccount)
.WithClaims(claimChallenge)
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
try
{
authResult = await _clientApp.AcquireTokenInteractive(scopes)
.WithClaims(claimChallenge)
.WithAccount(firstAccount)
.ExecuteAsync()
.ConfigureAwait(false);
}
// ...
Setelah aplikasi Anda siap untuk menangani tantangan klaim yang dikembalikan oleh sumber daya berkemampuan CAE, Anda dapat memberi tahu Microsoft Identity bahwa aplikasi Anda siap untuk CAE. Untuk melakukan ini di aplikasi MSAL Anda, bangun Klien Publik Anda menggunakan Kemampuan Klien ."cp1"
_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
.WithDefaultRedirectUri()
.WithAuthority(authority)
.WithClientCapabilities(new [] {"cp1"})
.Build();
Ketika kondisi ini terpenuhi, aplikasi dapat mengekstrak tantangan klaim dari header respons API seperti berikut:
try {
const response = await fetch(apiEndpoint, options);
if (response.status === 401 && response.headers.get('www-authenticate')) {
const authenticateHeader = response.headers.get('www-authenticate');
const claimsChallenge = parseChallenges(authenticateHeader).claims;
// use the claims challenge to acquire a new access token...
}
} catch(error) {
// ...
}
// helper function to parse the www-authenticate header
function parseChallenges(header) {
const schemeSeparator = header.indexOf(' ');
const challenges = header.substring(schemeSeparator + 1).split(',');
const challengeMap = {};
challenges.forEach((challenge) => {
const [key, value] = challenge.split('=');
challengeMap[key.trim()] = window.decodeURI(value.replace(/['"]+/g, ''));
});
return challengeMap;
}
Aplikasi Anda kemudian menggunakan tantangan klaim untuk memperoleh token akses baru untuk sumber daya.
const tokenRequest = {
claims: window.atob(claimsChallenge), // decode the base64 string
scopes: ['User.Read'],
account: msalInstance.getActiveAccount()
};
let tokenResponse;
try {
tokenResponse = await msalInstance.acquireTokenSilent(tokenRequest);
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
tokenResponse = await msalInstance.acquireTokenPopup(tokenRequest);
}
}
Setelah aplikasi siap untuk menangani tantangan klaim yang dikembalikan oleh sumber daya yang diaktifkan CAE, Anda dapat memberi tahu Identitas Microsoft bahwa aplikasi Anda siap untuk CAE dengan menambahkan properti clientCapabilities
di konfigurasi MSAL.
const msalConfig = {
auth: {
clientId: 'Enter_the_Application_Id_Here',
clientCapabilities: ["CP1"]
// remaining settings...
}
}
const msalInstance = new PublicClientApplication(msalConfig);
Ketika kondisi ini terpenuhi, aplikasi dapat mengekstrak tantangan klaim dari header respons API seperti berikut:
import msal # pip install msal
import requests # pip install requests
import www_authenticate # pip install www-authenticate==0.9.2
# Once your application is ready to handle the claim challenge returned by a CAE-enabled resource, you can tell Microsoft Identity your app is CAE-ready. To do this in your MSAL application, build your Public Client using the Client Capabilities of "cp1".
app = msal.PublicClientApplication("your_client_id", client_capabilities=["cp1"])
...
# When these conditions are met, the app can extract the claims challenge from the API response header as follows:
response = requests.get("<your_resource_uri_here>")
if response.status_code == 401 and response.headers.get('WWW-Authenticate'):
parsed = www_authenticate.parse(response.headers['WWW-Authenticate'])
claims = parsed.get("bearer", {}).get("claims")
# Your app would then use the claims challenge to acquire a new access token for the resource.
if claims:
auth_result = app.acquire_token_interactive(["scope"], claims_challenge=claims)
Mendeklarasikan dukungan untuk Kemampuan Klien CP1
Dalam konfigurasi aplikasi, Anda harus menyatakan bahwa aplikasi Anda mendukung CAE dengan menyertakan CP1
kemampuan klien. Ini ditentukan dengan menggunakan client_capabilities
properti JSON.
{
"client_id" : "<your_client_id>",
"authorization_user_agent" : "DEFAULT",
"redirect_uri" : "msauth://<pkg>/<cert_hash>",
"multiple_clouds_supported":true,
"broker_redirect_uri_registered": true,
"account_mode": "MULTIPLE",
"client_capabilities": "CP1",
"authorities" : [
{
"type": "AAD",
"audience": {
"type": "AzureADandPersonalMicrosoftAccount"
}
}
]
}
Menanggapi Tantangan CAE saat Runtime
Buat permintaan ke sumber daya, jika respons berisi tantangan klaim, ekstrak, dan masukkan kembali ke MSAL untuk digunakan dalam permintaan berikutnya.
final HttpURLConnection connection = ...;
final int responseCode = connection.getResponseCode();
// Check the response code...
if (200 == responseCode) {
// ...
} else if (401 == responseCode) {
final String authHeader = connection.getHeaderField("WWW-Authenticate");
if (null != authHeader) {
final ClaimsRequest claimsRequest = WWWAuthenticateHeader
.getClaimsRequestFromWWWAuthenticateHeaderValue(authHeader);
// Feed the challenge back into MSAL, first silently, then interactively if required
final AcquireTokenSilentParameters silentParameters = new AcquireTokenSilentParameters.Builder()
.fromAuthority(authority)
.forAccount(account)
.withScopes(scope)
.withClaims(claimsRequest)
.build();
try {
final IAuthenticationResult silentRequestResult = mPublicClientApplication.acquireTokenSilent(silentParameters);
// If successful - your business logic goes here...
} catch (final Exception e) {
if (e instanceof MsalUiRequiredException) {
// Retry the request interactively, passing in any claims challenge...
}
}
}
} else {
// ...
}
// Don't forget to close your connection
Cuplikan kode berikut menjelaskan alur memperoleh token secara diam-diam, melakukan panggilan http ke penyedia sumber daya, lalu menangani kasus CAE. Panggilan interaksi tambahan mungkin diperlukan jika panggilan senyap gagal dengan klaim.
Mendeklarasikan dukungan untuk kemampuan klien CP1
Dalam konfigurasi aplikasi, Anda harus menyatakan bahwa aplikasi Anda mendukung CAE dengan menyertakan CP1
kemampuan klien. Ini ditentukan dengan menggunakan clientCapabilities
properti .
let clientConfigurations = MSALPublicClientApplicationConfig(clientId: "contoso-app-ABCDE-12345",
redirectUri: "msauth.com.contoso.appbundle://auth",
authority: try MSALAuthority(url: URL(string: "https://login.microsoftonline.com/organizations")!))
clientConfigurations.clientApplicationCapabilities = ["CP1"]
let applicationContext = try MSALPublicClientApplication(configuration: clientConfigurations)
Terapkan fungsi pembantu untuk mengurai tantangan klaim.
func parsewwwAuthenticateHeader(headers:Dictionary<AnyHashable, Any>) -> String? {
// !! This is a sample code and is not validated, please provide your own implementation or fully test the sample code provided here.
// Can also refer here for our internal implementation: https://github.com/AzureAD/microsoft-authentication-library-common-for-objc/blob/dev/IdentityCore/src/webview/embeddedWebview/challangeHandlers/MSIDPKeyAuthHandler.m#L112
guard let wwwAuthenticateHeader = headers["WWW-Authenticate"] as? String else {
// did not find the header, handle gracefully
return nil
}
var parameters = [String: String]()
// regex mapping
let regex = try! NSRegularExpression(pattern: #"(\w+)="([^"]*)""#)
let matches = regex.matches(in: wwwAuthenticateHeader, range: NSRange(wwwAuthenticateHeader.startIndex..., in: wwwAuthenticateHeader))
for match in matches {
if let keyRange = Range(match.range(at: 1), in: wwwAuthenticateHeader),
let valueRange = Range(match.range(at: 2), in: wwwAuthenticateHeader) {
let key = String(wwwAuthenticateHeader[keyRange])
let value = String(wwwAuthenticateHeader[valueRange])
parameters[key] = value
}
}
guard let jsonData = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) else {
// cannot convert params into json date, end gracefully
return nil
}
return String(data: jsonData, encoding: .utf8)
}
Menangkap & mengurai tantangan 401 / klaim.
let response = .... // HTTPURLResponse object from 401'd service response
switch response.statusCode {
case 200:
// ...succeeded!
break
case 401:
let headers = response.allHeaderFields
// Parse header fields
guard let wwwAuthenticateHeaderString = self.parsewwwAuthenticateHeader(headers: headers) else {
// 3.7 no valid wwwAuthenticateHeaderString is returned from header, end gracefully
return
}
let claimsRequest = MSALClaimsRequest(jsonString: wwwAuthenticateHeaderString, error: nil)
// Create claims request
let parameters = MSALSilentTokenParameters(scopes: "Enter_the_Protected_API_Scopes_Here", account: account)
parameters.claimsRequest = claimsRequest
// Acquire token silently again with the claims challenge
applicationContext.acquireTokenSilent(with: parameters) { (result, error) in
if let error = error {
// error happened end flow gracefully, and handle error. (e.g. interaction required)
return
}
guard let result = result else {
// no result end flow gracefully
return
}
// Success - You got a token!
}
break
default:
break
}
Ketika kondisi ini terpenuhi, aplikasi dapat mengekstrak tantangan klaim dari header respons API seperti berikut:
Mengiklankan kemampuan klien.
client, err := New("client-id", WithAuthority(authority), WithClientCapabilities([]string{"cp1"}))
uraikan WWW-Authenticate
header dan berikan tantangan yang dihasilkan ke MSAL-Go.
// No snippet provided at this time
Mencoba memperoleh token secara diam-diam dengan tantangan klaim.
var ar AuthResult;
ar, err := client.AcquireTokenSilent(ctx, tokenScope, public.WithClaims(claims))
Anda dapat menguji aplikasi Anda dengan memasukkan pengguna ke aplikasi, lalu menggunakan portal Azure untuk mencabut sesi pengguna. Saat aplikasi memanggil API yang diaktifkan CAE di lain waktu, pengguna akan diminta untuk mengotorisasi ulang.