You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift/MSAL异步调用时出现‘internal保护级别导致无法访问’错误,但原完成块代码无此问题

Swift/MSAL异步调用时出现‘internal保护级别导致无法访问’错误,但原完成块代码无此问题

我来帮你分析这个问题,看起来你在把MSAL的回调式调用改成async/await后遇到了访问权限问题,而原来的代码却能正常运行,这大概率和API的访问权限或者MSAL的API风格变化有关,下面给你拆解原因和解决方案:

可能的原因分析

  • MSAL API版本迭代的变化:新版MSAL已经把Objective-C风格的getGlobalId()、getUserName()这类getter方法,替换成了更符合Swift习惯的属性(比如globalId、userName),原来的getter方法被标记为internal不再对外公开。你的旧代码可能基于老版本MSAL编写,当时这些方法还是公开的,所以没报错。
  • 自定义异步封装的类型问题:你自己封装的B2CAuthApi.logInAsync方法,可能在返回结果时,result.account的类型不是公开的MSALAccount,而是MSAL内部的子类(比如MSALAccountInternal),导致你在外部无法访问这些内部方法。

解决方案

方案1:改用MSAL官方的异步API(推荐)

MSAL本身已经提供了async/await版本的API,不需要手动封装续体,直接用官方方法能确保拿到正确的公开类型:

public func logIn(msalApplication: MSALPublicClientApplication, webViewParameters: MSALWebviewParameters) async throws {
    let interactiveParameters = MSALInteractiveTokenParameters(scopes: [], webviewParameters: webViewParameters)
    let result = try await msalApplication.acquireToken(with: interactiveParameters)
    
    if !result.accessToken.isEmpty {
        self.accountToken = result.accessToken
    }
    self.accountTokenExpiration = result.expiresOn
    self.account = result.account
    self.isAuthenticated = true
    
    // 改用Swift风格的属性访问
    self.accountGlobalId = result.account.globalId
    self.accountUserName = result.account.userName
}

方案2:修复自定义封装的logInAsync方法

如果必须使用自己的封装,要确保返回的结果类型是公开的MSALResult,并且account是MSALAccount类型:
先检查你的B2CAuthApi.logInAsync实现,确保续体返回正确的公开类型:

static func logInAsync(msalApplication: MSALPublicClientApplication, webViewParameters: MSALWebviewParameters) async throws -> MSALResult {
    return try await withCheckedThrowingContinuation { continuation in
        let interactiveParameters = MSALInteractiveTokenParameters(scopes: [], webviewParameters: webViewParameters)
        msalApplication.acquireToken(with: interactiveParameters) { result, error in
            if let error = error {
                continuation.resume(throwing: error)
                return
            }
            guard let result = result else {
                continuation.resume(throwing: NSError(domain: "B2CAuth", code: -1, userInfo: [NSLocalizedDescriptionKey: "Expected result but got nil"]))
                return
            }
            continuation.resume(returning: result)
        }
    }
}

然后同样将getter方法替换成属性访问:

self.accountGlobalId = result.account.globalId
self.accountUserName = result.account.userName

方案3:显式指定类型适配旧版本(不推荐)

如果你的项目依赖的MSAL版本确实还在使用getter方法,可能是自定义封装时类型推断出了问题,可以显式指定account的类型为MSALAccount:

guard let account = result.account as? MSALAccount else {
    preconditionFailure("Expected MSALAccount type")
}
self.accountGlobalId = account.getGlobalId()
self.accountUserName = account.getUserName()

不过这个方案不推荐,因为MSAL的API风格已经向Swift属性迁移,老方法后续可能会被废弃。

备注:内容来源于stack exchange,提问作者lcj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 09:18:04