处理 MSAL for iOS/macOS 中的错误和异常
本文概述不同类型的错误,并提供处理常见登录错误的相关建议。
MSAL 错误处理基础知识
Microsoft 身份验证库 (MSAL) 中的异常旨在帮助应用开发者进行故障排除,而不会向最终用户显示。 异常消息未经本地化。
处理异常和错误时,可以使用异常类型本身和错误代码来区分不同的异常。 有关错误代码的列表,请参阅 Microsoft Entra 身份验证和授权错误代码。
在登录体验期间,可能会遇到有关许可、条件访问(MFA、设备管理、基于位置的限制)、令牌颁发和兑换以及用户属性的错误。
以下部分提供了有关应用错误处理的更多详细信息。
MSAL for iOS/macOS 中的错误处理
MSALError 枚举中列出了适用于 iOS 和 macOS 的 MSAL 完整错误列表。
生成的所有 MSAL 错误都以 MSALErrorDomain
域返回。
对于系统错误,MSAL 会从系统 API 返回原始 NSError
。 例如,如果由于缺少网络连接,令牌获取失败,则 MSAL 会返回包含 NSURLErrorDomain
域和 NSURLErrorNotConnectedToInternet
代码的错误。
建议在客户端上至少处理以下两个 MSAL 错误:
MSALErrorInteractionRequired
:用户必须执行交互式请求。 很多条件都可能会导致此错误,例如身份验证会话过期或需要额外的身份验证要求。 调用 MSAL 交互式令牌获取 API 以进行恢复。MSALErrorServerDeclinedScopes
:部分或全部作用域已被拒绝。 决定是继续使用唯一允许的作用域,还是停止登录过程。
注意
MSALInternalError
枚举应仅用于引用和调试。 请勿尝试在运行时自动处理这些错误。 如果应用遇到属于 MSALInternalError
的任何错误,则可能希望显示一条面向用户的通用消息,说明所发生的情况。
例如,MSALInternalErrorBrokerResponseNotReceived
表示用户未完成身份验证并已手动返回到应用。 在这种情况下,应用应显示一条通用错误消息,说明身份验证未完成,并建议他们尝试再次进行身份验证。
以下 Objective-C 示例代码演示了处理某些常见错误状况的最佳做法。
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.
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.
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)
条件访问和声明质询
以静默方式获取令牌时,如果你尝试访问的 API 需要条件访问声明质询(例如 MFA 策略),则应用程序可能会收到错误。
处理此错误的模式是使用 MSAL 以交互方式获取令牌。 这会提示用户,并使他们能够满足所需的条件访问策略。
在某些情况下调用需要条件访问的 API 时,API 返回的错误中可能会包含声明质询。 例如,如果条件访问策略要求使用托管设备 (Intune),则错误将类似于 AADSTS53000:需要管理你的设备才能访问此资源。 在这种情况下,可以在令牌获取调用中传递声明,使系统提示用户,以满足相应的策略。
借助适用于 iOS 和 macOS 的 MSAL,你可以在交互式和静默令牌获取方案中请求特定的声明。
要请求自定义声明,请在 MSALSilentTokenParameters
或 MSALInteractiveTokenParameters
中指定 claimsRequest
。
有关详细信息,请参阅使用适用于 iOS 和 macOS 的 MSAL 请求自定义声明。
出现错误和异常后重试
调用 MSAL 时,应实现自己的重试策略。 MSAL 会对 Microsoft Entra 服务进行 HTTP 调用,有时会失败。 例如网络崩溃或服务器重载。
HTTP 429
如果服务令牌服务器 (STS) 因请求过多而重载,则将返回 HTTP 错误 429,并在 Retry-After
响应字段中提示还要多久才能重试。
后续步骤
请考虑启用 MSAL for iOS/macOS 中的日志记录,以帮助你诊断和调试问题。