Eftersom risk och princip utvärderas i realtid kan vissa resurs-API:ers tokenlivslängd öka med upp till 28 timmar. Dessa långlivade token uppdateras proaktivt av Microsoft Authentication Library (MSAL), vilket ökar återhämtningstiden för dina program.
Om du vill använda CAE måste både appen och resurs-API:et som den har åtkomst till vara CAE-aktiverade. Om ett resurs-API implementerar CAE och ditt program deklarerar att det kan hantera CAE tar appen emot CAE-token för den resursen. Om du därför deklarerar din app CAE-klar måste ditt program hantera CAE-anspråksutmaningen för alla resurs-API:er som accepterar Åtkomsttoken för Microsoft Identity.
Att förbereda koden för att stödja CAE-aktiverade resurser begränsar dock inte dess möjlighet att arbeta med API:er som inte stöder CAE. Om appen inte hanterar CAE-svar korrekt kan den upprepade gånger försöka utföra ett API-anrop igen med en token som är tekniskt giltig men som återkallas på grund av CAE.
Börja med att lägga till kod för att hantera svar från resurs-API:et som avvisar anropet på grund av CAE. Med CAE returnerar API:er en 401-status och en WWW-Authenticate
rubrik när åtkomsttoken återkallas eller API:et identifierar en ändring i den IP-adress som används. Rubriken WWW-Authenticate
innehåller en anspråksutmaning som programmet kan använda för att hämta en ny åtkomsttoken.
När dessa villkor uppfylls kan appen extrahera och avkoda anspråksutmaningen med hjälp av klassen MSAL.NETWwwAuthenticateParameters
.
if (APIresponse.IsSuccessStatusCode)
{
// ...
}
else
{
if (APIresponse.StatusCode == System.Net.HttpStatusCode.Unauthorized
&& APIresponse.Headers.WwwAuthenticate.Any())
{
string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(APIresponse.Headers);
Appen använder sedan anspråksutmaningen för att hämta en ny åtkomsttoken för resursen.
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);
}
// ...
När ditt program är redo att hantera anspråksutmaningen som returneras av en CAE-aktiverad resurs kan du berätta för Microsoft Identity att din app är CAE-redo. Om du vill göra detta i ditt MSAL-program skapar du den offentliga klienten med hjälp av "cp1"
klientfunktionerna i .
_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
.WithDefaultRedirectUri()
.WithAuthority(authority)
.WithClientCapabilities(new [] {"cp1"})
.Build();
När dessa villkor uppfylls kan appen extrahera anspråksutmaningen från API-svarshuvudet på följande sätt:
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;
}
Appen använder sedan anspråksutmaningen för att hämta en ny åtkomsttoken för resursen.
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);
}
}
När ditt program är redo att hantera anspråksutmaningen som returneras av en CAE-aktiverad resurs kan du berätta för Microsoft Identity att din app är CAE-redo genom att lägga till en clientCapabilities
egenskap i MSAL-konfigurationen.
const msalConfig = {
auth: {
clientId: 'Enter_the_Application_Id_Here',
clientCapabilities: ["CP1"]
// remaining settings...
}
}
const msalInstance = new PublicClientApplication(msalConfig);
När dessa villkor uppfylls kan appen extrahera anspråksutmaningen från API-svarshuvudet på följande sätt:
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)
Deklarera stöd för CP1-klientfunktionen
I programkonfigurationen måste du deklarera att programmet stöder CAE genom att inkludera CP1
klientfunktionen. Detta anges med hjälp av JSON-egenskapen client_capabilities
.
{
"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"
}
}
]
}
Svara på CAE-utmaningar vid körning
Gör en begäran till en resurs, om svaret innehåller en anspråksutmaning, extrahera den och mata tillbaka den till MSAL för användning i nästa begäran.
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
Följande kodfragment beskriver flödet för att hämta en token tyst, göra ett http-anrop till resursprovidern och sedan hantera ett CAE-ärende. Ett extra interaktionsanrop kan krävas om det tysta samtalet misslyckades med anspråk.
Deklarera stöd för CP1-klientkapacitet
I programkonfigurationen måste du deklarera att programmet stöder CAE genom att inkludera CP1
klientfunktionen. Detta anges med hjälp clientCapabilities
av egenskapen .
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)
Implementera en hjälpfunktion för att parsa anspråksutmaningar.
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 & parsa 401/anspråksutmaningar.
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
}
När dessa villkor uppfylls kan appen extrahera anspråksutmaningen från API-svarshuvudet på följande sätt:
Annonsera klientfunktioner.
client, err := New("client-id", WithAuthority(authority), WithClientCapabilities([]string{"cp1"}))
parsa WWW-Authenticate
huvudet och skicka den resulterande utmaningen till MSAL-Go.
// No snippet provided at this time
Försök att hämta en token tyst med anspråksutmaningen.
var ar AuthResult;
ar, err := client.AcquireTokenSilent(ctx, tokenScope, public.WithClaims(claims))
Du kan testa ditt program genom att logga in en användare och sedan använda Azure Portal för att återkalla användarens session. Nästa gång appen anropar DET CAE-aktiverade API:et uppmanas användaren att autentisera igen.