Obsługa błędów i wyjątków w usłudze MSAL dla systemu iOS/macOS

Ten artykuł zawiera omówienie różnych typów błędów i zaleceń dotyczących obsługi typowych błędów logowania.

Podstawy obsługi błędów w MSAL

Wyjątki w Microsoft Authentication Library (MSAL) są przeznaczone dla deweloperów aplikacji do rozwiązywania problemów, a nie wyświetlania użytkownikom końcowym. Komunikaty o wyjątkach nie są zlokalizowane.

Podczas przetwarzania wyjątków i błędów można użyć samego typu wyjątku i kodu błędu, aby odróżnić wyjątki. Aby uzyskać listę kodów błędów, zobacz Microsoft Entra kody błędów uwierzytelniania i autoryzacji.

Podczas logowania mogą wystąpić błędy dotyczące zgody, dostępu warunkowego (MFA, Zarządzanie urządzeniami, ograniczeń opartych na lokalizacji), wystawiania i realizacji tokenów oraz właściwości użytkownika.

Poniższa sekcja zawiera więcej szczegółowych informacji na temat obsługi błędów dla aplikacji.

Obsługa błędów w usłudze MSAL dla systemu iOS/macOS

Pełna lista błędów MSAL dla systemów iOS i macOS znajduje się w enum MSALError.

Wszystkie błędy generowane przez bibliotekę MSAL są zwracane w domenie MSALErrorDomain.

W przypadku błędów systemowych biblioteka MSAL zwraca oryginalny element NSError z systemowego interfejsu API. Jeśli na przykład pozyskiwanie tokenu zakończy się niepowodzeniem z powodu braku łączności sieciowej, biblioteka MSAL zwraca błąd z NSURLErrorDomain domeną i NSURLErrorNotConnectedToInternet kodem.

Zalecamy obsłużenie po stronie klienta co najmniej następujących dwóch błędów MSAL:

  • MSALErrorInteractionRequired: Użytkownik musi wykonać żądanie interakcyjne. Istnieje wiele warunków, które mogą prowadzić do tego błędu, takiego jak wygasła sesja uwierzytelniania lub potrzeba dodatkowych wymagań dotyczących uwierzytelniania. Wywołaj interfejs API interakcyjnego pozyskiwania tokenu biblioteki MSAL, aby przywrócić działanie.

  • MSALErrorServerDeclinedScopes: Niektóre lub wszystkie zakresy zostały odrzucone. Zdecyduj, czy chcesz kontynuować tylko przyznane zakresy, czy zatrzymać proces logowania.

Note

Wyliczenie MSALInternalError powinno być używane tylko do celów referencyjnych i debugowania. Nie próbuj automatycznie obsługiwać tych błędów w czasie wykonywania. Jeśli twoja aplikacja napotka jakiekolwiek błędy, które mieszczą się w obszarze MSALInternalError, może być konieczne wyświetlenie ogólnego komunikatu z informacją o tym, co się stało.

Na przykład oznacza, MSALInternalErrorBrokerResponseNotReceived że użytkownik nie ukończył uwierzytelniania i ręcznie wrócił do aplikacji. W takim przypadku aplikacja powinna wyświetlić ogólny komunikat o błędzie z wyjaśnieniem, że uwierzytelnianie nie zostało ukończone i sugeruje, że spróbuje uwierzytelnić się ponownie.

Poniższy Objective-C przykładowy kod przedstawia najlepsze rozwiązania dotyczące obsługi niektórych typowych warunków błędów.

    MSALInteractiveTokenParameters *interactiveParameters = ...;
    MSALSilentTokenParameters *silentParameters = ...;
    
    MSALCompletionBlock completionBlock;
    __block __weak MSALCompletionBlock weakCompletionBlock;
    
    weakCompletionBlock = completionBlock = ^(MSALResult *result, NSError *error)
    {
        if (!error)
        {
            // Use result.accessToken
            NSString *accessToken = result.accessToken;
            return;
        }
        
        if ([error.domain isEqualToString:MSALErrorDomain])
        {
            switch (error.code)
            {
                case MSALErrorInteractionRequired:
                {
                    // Interactive auth will be required
                    [application acquireTokenWithParameters:interactiveParameters
                                            completionBlock:weakCompletionBlock];
                    
                    break;
                }
                    
                case MSALErrorServerDeclinedScopes:
                {
                    // These are list of granted and declined scopes.
                    NSArray *grantedScopes = error.userInfo[MSALGrantedScopesKey];
                    NSArray *declinedScopes = error.userInfo[MSALDeclinedScopesKey];
                    
                    // To continue acquiring token for granted scopes only, do the following
                    silentParameters.scopes = grantedScopes;
                    [application acquireTokenSilentWithParameters:silentParameters
                                                  completionBlock:weakCompletionBlock];
                    
                    // Otherwise, instead, handle error fittingly to the application context
                    break;
                }
                    
                case MSALErrorServerProtectionPoliciesRequired:
                {
                    // Integrate the Intune SDK and call the
                    // remediateComplianceForIdentity:silent: API.
                    // Handle this error only if you integrated Intune SDK.
                    // See more info here: https://aka.ms/intuneMAMSDK
                    
                    break;
                }
                    
                case MSALErrorUserCanceled:
                {
                    // The user cancelled the web auth session.
                    // You may want to ask the user to try again.
                    // Handling of this error is optional.
                    
                    break;
                }
                    
                case MSALErrorInternal:
                {
                    // Log the error, then inspect the MSALInternalErrorCodeKey
                    // in the userInfo dictionary.
                    // Display generic error message to the end user
                    // More detailed information about the specific error
                    // under MSALInternalErrorCodeKey can be found in MSALInternalError enum.
                    NSLog(@"Failed with error %@", error);
                    
                    break;
                }
                    
                default:
                    NSLog(@"Failed with unknown MSAL error %@", error);
                    
                    break;
            }
            
            return;
        }
        
        // Handle no internet connection.
        if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet)
        {
            NSLog(@"No internet connection.");
            return;
        }
        
        // Other errors may require trying again later,
        // or reporting authentication problems to the user.
        NSLog(@"Failed with error %@", error);
    };
    
    // Acquire token silently
    [application acquireTokenSilentWithParameters:silentParameters
                                  completionBlock:completionBlock];

     // or acquire it interactively.
     [application acquireTokenWithParameters:interactiveParameters
                             completionBlock:completionBlock];
    let interactiveParameters: MSALInteractiveTokenParameters = ...
    let silentParameters: MSALSilentTokenParameters = ...
            
    var completionBlock: MSALCompletionBlock!
    completionBlock = { (result: MSALResult?, error: Error?) in
                
        if let result = result
        {
            // Use result.accessToken
            let accessToken = result.accessToken
            return
        }

        guard let error = error as NSError? else { return }

        if error.domain == MSALErrorDomain, let errorCode = MSALError(rawValue: error.code)
        {
            switch errorCode
            {
                case .interactionRequired:
                    // Interactive auth will be required
                    application.acquireToken(with: interactiveParameters, completionBlock: completionBlock)

                case .serverDeclinedScopes:
                    let grantedScopes = error.userInfo[MSALGrantedScopesKey]
                    let declinedScopes = error.userInfo[MSALDeclinedScopesKey]

                    if let scopes = grantedScopes as? [String] {
                        silentParameters.scopes = scopes
                        application.acquireTokenSilent(with: silentParameters, completionBlock: completionBlock)
                    }
                        
                    case .serverProtectionPoliciesRequired:
                        // Integrate the Intune SDK and call the
                        // remediateComplianceForIdentity:silent: API.
                        // Handle this error only if you integrated Intune SDK.
                        // See more info here: https://aka.ms/intuneMAMSDK
                        break
                        
                    case .userCanceled:
                       // The user cancelled the web auth session.
                       // You may want to ask the user to try again.
                       // Handling of this error is optional.
                       break
                        
                    case .internal:
                        // Log the error, then inspect the MSALInternalErrorCodeKey
                        // in the userInfo dictionary.
                        // Display generic error message to the end user
                        // More detailed information about the specific error
                        // under MSALInternalErrorCodeKey can be found in MSALInternalError enum.
                        print("Failed with error \(error)");
                        
                    default:
                        print("Failed with unknown MSAL error \(error)")
            }
        }
                
        // Handle no internet connection.
        if error.domain == NSURLErrorDomain && error.code == NSURLErrorNotConnectedToInternet
        {
            print("No internet connection.")
            return
        }
                
        // Other errors may require trying again later,
        // or reporting authentication problems to the user.
        print("Failed with error \(error)");    
    }
   
    // Acquire token silently
    application.acquireToken(with: interactiveParameters, completionBlock: completionBlock)
 
    // or acquire it interactively.
    application.acquireTokenSilent(with: silentParameters, completionBlock: completionBlock)

Wyzwania związane z dostępem warunkowym i oświadczeniami

Podczas cichego uzyskiwania tokenów w aplikacji może wystąpić błąd, gdy interfejs API, do którego próbujesz uzyskać dostęp, wymaga żądania oświadczeń w ramach dostępu warunkowego, na przykład zasady uwierzytelniania wieloskładnikowego.

Sposób obsługi tego błędu polega na interaktywnym uzyskaniu tokenu za pomocą MSAL. Spowoduje to wyświetlenie użytkownikowi monitu i umożliwi mu spełnienie wymagań określonych przez wymaganą politykę dostępu warunkowego.

W niektórych przypadkach podczas wywoływania interfejsu API wymagającego dostępu warunkowego możesz otrzymać wyzwanie dotyczące oświadczeń w błędzie z interfejsu API. Na przykład jeśli zasada dostępu warunkowego wymaga zarządzanego urządzenia (Intune), błąd będzie wyglądał mniej więcej tak: AADSTS53000: Twoje urządzenie musi być zarządzane, aby uzyskać dostęp do tego zasobu lub czymś podobnym. W takim przypadku można przekazać oświadczenia w wywołaniu tokenu uzyskiwania, aby użytkownik był monitowany o spełnienie odpowiednich zasad.

Biblioteka MSAL dla systemów iOS i macOS umożliwia żądanie określonych oświadczeń zarówno w scenariuszach pozyskiwania tokenów interakcyjnych, jak i dyskretnych.

Aby zażądać niestandardowych oświadczeń, określ claimsRequest w MSALSilentTokenParameters lub MSALInteractiveTokenParameters.

Aby uzyskać więcej informacji, zobacz Request custom claims using MSAL for iOS and macOS (Żądanie oświadczeń niestandardowych przy użyciu biblioteki MSAL dla systemów iOS i macOS ).

Ponawianie próby po wystąpieniu błędów i wyjątków

Oczekuje się od użytkownika zaimplementowania własnych zasad ponawiania prób podczas wywoływania biblioteki MSAL. Biblioteka MSAL wysyła żądania HTTP do usługi Microsoft Entra i sporadycznie mogą występować niepowodzenia. Na przykład sieć może spaść lub serwer jest przeciążony.

HTTP 429

Gdy serwer tokenów usługi (STS) jest przeciążony zbyt wieloma żądaniami, zwraca błąd HTTP 429 z wskazówką o tym, jak długo można spróbować ponownie w Retry-After polu odpowiedzi.

Następne kroki

Rozważ włączenie rejestrowania w MSAL w systemach iOS/macOS, aby ułatwić diagnozowanie i debugowanie problemów.