Weil Risiken und Richtlinien in Echtzeit ausgewertet werden. kann dies bei einigen Ressourcen-APIs die Lebensdauer eines Tokens um bis zu 28 Stunden verlängern. Diese langlebigen Token werden von der Microsoft Authentication Library (MSAL) proaktiv aktualisiert, wodurch die Resilienz Ihrer Anwendungen steigt.
Damit die fortlaufende Zugriffsevaluierung (Continuous Access Evaluation, CAE) genutzt werden kann, muss dieses Feature sowohl für Ihre App als auch für die Ressourcen-API aktiviert werden, die auf die App zugreift. Wenn eine Ressourcen-API CAE implementiert und in Ihrer App deklariert wurde, dass sie das Feature verarbeiten kann, erhält die App CAE-Token für diese Ressource. Aus diesem Grund gilt Folgendes: Wenn Sie Ihre App als CAE-fähig deklarieren, muss die App die CAE-Anspruchsabfrage für alle Ressourcen-APIs verarbeiten, die Microsoft Identity-Zugriffstoken akzeptieren.
Die Vorbereitung Ihres Codes zur Unterstützung von CAE-fähigen Ressourcen beschränkt jedoch nicht die Fähigkeit, mit APIs zu arbeiten, die keine CAE unterstützen. Wenn Ihre App CAE-Antworten nicht ordnungsgemäß verarbeitet, wird ein API-Aufruf möglicherweise mithilfe eines technisch gültigen Tokens wiederholt, aber aufgrund der CAE widerrufen.
Fügen Sie als Erstes Code hin, um eine Antwort von der Ressourcen-API zu verarbeiten, die den Aufruf aufgrund von CAE ablehnt. Mit CAE geben APIs einen 401-Statuscode sowie einen WWW-Authenticate
-Header zurück, wenn das Zugriffstoken widerrufen wird oder die API eine Änderung in der verwendeten IP-Adresse erkennt. Der WWW-Authenticate
-Header enthält eine Anspruchsabfrage, mit der die Anwendung ein neues Zugriffstoken abrufen kann.
Wenn diese Bedingungen erfüllt sind, kann die App die Anspruchsabfrage unter Verwendung der MSAL.NET-Klasse WwwAuthenticateParameters
extrahieren und decodieren.
if (APIresponse.IsSuccessStatusCode)
{
// ...
}
else
{
if (APIresponse.StatusCode == System.Net.HttpStatusCode.Unauthorized
&& APIresponse.Headers.WwwAuthenticate.Any())
{
string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(APIresponse.Headers);
Dann verwendet Ihre App die Anspruchsabfrage, um ein neues Zugriffstoken für die Ressource abzurufen.
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);
}
// ...
Sobald Ihre Anwendung dazu bereit ist, die von einer für CAE aktivierten Ressource zurückgegebene Anspruchsabfrage zu verarbeiten, können Sie Microsoft Identity mitteilen, dass Ihre Anwendung CAE-fähig ist. Um dies in Ihrer MSAL-Anwendung umzusetzen, erstellen Sie Ihren öffentlichen Client mit den Clientfunktionen von "cp1"
.
_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
.WithDefaultRedirectUri()
.WithAuthority(authority)
.WithClientCapabilities(new [] {"cp1"})
.Build();
Wenn diese Bedingungen erfüllt sind, kann die App die Anspruchsabfrage aus dem API-Antwortheader wie folgt extrahieren:
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;
}
Dann verwendet Ihre App die Anspruchsabfrage, um ein neues Zugriffstoken für die Ressource abzurufen.
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);
}
}
Sobald Ihre Anwendung dazu bereit ist, die von einer für CAE aktivierten Ressource zurückgegebene Anspruchsabfrage zu verarbeiten, können Sie Microsoft Identity mitteilen, dass Ihre Anwendung CAE-fähig ist, indem Sie eine clientCapabilities
-Eigenschaft in der MSAL-Konfiguration hinzufügen.
const msalConfig = {
auth: {
clientId: 'Enter_the_Application_Id_Here',
clientCapabilities: ["CP1"]
// remaining settings...
}
}
const msalInstance = new PublicClientApplication(msalConfig);
Wenn diese Bedingungen erfüllt sind, kann die App die Anspruchsabfrage aus dem API-Antwortheader wie folgt extrahieren:
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)
Deklarieren der Unterstützung für die CP1-Clientfunktion
In Ihrer Anwendungskonfiguration müssen Sie deklarieren, dass Ihre Anwendung CAE unterstützt, indem Sie die CP1
-Clientfunktion einschließen. Dies wird mithilfe der JSON-Eigenschaft client_capabilities
angegeben.
{
"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"
}
}
]
}
Reagieren auf CAE-Herausforderungen zur Runtime
Stellen Sie eine Anfrage an eine Ressource. Wenn die Antwort eine Anspruchsabfrage enthält, extrahieren Sie diese, und geben Sie sie zur Verwendung in der nächsten Anfrage wieder in MSAL ein.
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
Die folgenden Codeausschnitte beschreiben den das Abrufen eines Tokens im Hintergrund, führen einen HTTP-Aufruf an den Ressourcenanbieter durch und behandeln dann einen CAE-Fall. Ein zusätzlicher Interaktionsaufruf kann erforderlich sein, wenn der automatische Aufruf mit Ansprüchen fehlgeschlagen ist.
Deklarieren der Unterstützung für CP1-Clientfunktion
In Ihrer Anwendungskonfiguration müssen Sie deklarieren, dass Ihre Anwendung CAE unterstützt, indem Sie die CP1
-Clientfunktion einschließen. Dies wird mithilfe der Eigenschaft clientCapabilities
angegeben.
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)
Implementieren Sie eine Hilfsfunktion zum Analysieren von Anspruchsproblemen.
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)
}
Catch & parse 401 / Anspruchsabfragen.
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
}
Wenn diese Bedingungen erfüllt sind, kann die App die Anspruchsabfrage aus dem API-Antwortheader wie folgt extrahieren:
Ankündigung von Clientfunktionen.
client, err := New("client-id", WithAuthority(authority), WithClientCapabilities([]string{"cp1"}))
parsen Sie den WWW-Authenticate
-Header, und übergeben Sie die resultierende Abfrage an MSAL-Go.
// No snippet provided at this time
Versuchen Sie, ein Token im Hintergrund mit der Anspruchsabfrage abzurufen.
var ar AuthResult;
ar, err := client.AcquireTokenSilent(ctx, tokenScope, public.WithClaims(claims))
Sie können Ihre Anwendung testen, indem Sie einen Benutzer anmelden und dann das Azure-Portal verwenden, um die Sitzungen des Benutzers zu widerrufen. Wenn die App das nächste Mal die API mit aktivierter CAE aufruft, wird der Benutzer aufgefordert, sich erneut zu authentifizieren.