Leverage enterprise identity and authentication
Privacy & Security 进阶 20m

利用企业身份和认证

Leverage enterprise identity and authentication

2020年6月24日

在 Apple 官方观看视频

一句话判断

iOS 14 的 Device Authentication 和平台 SSO 让企业 App 可以无缝使用公司的身份认证系统,员工不再需要逐个 App 登录——系统级的单点登录终于来到了 iOS。

这场 Session 讲了什么

面向企业开发者和 IT 管理员,Session 介绍了 iOS 14 中与身份认证相关的新功能。重点内容包括平台 SSO(Platform SSO)和 Device Authentication。

平台 SSO 允许用户在设备级别登录一次企业身份,之后所有支持 SSO 的企业 App 都自动获得认证,不需要再次登录。这个功能通过 ASAuthorizationProvider 扩展实现,配合 MDM 部署到企业设备上。Device Authentication 则允许企业 App 使用设备的安全芯片(Secure Enclave)来证明设备的身份,而不依赖用户名密码。Session 还介绍了如何将这两项功能与企业现有的 Identity Provider(如 Okta、Azure AD)集成。

值得深挖的点

Platform SSO 的工作原理

Platform SSO 的核心是 ASAuthorizationPlatformSSOProvider。它的工作流程是:用户在设备设置中注册企业身份(一次性的),系统将认证令牌存储在 Secure Enclave 中。当企业 App 需要认证时,调用 ASAuthorization API,系统自动使用存储的令牌完成认证。整个过程对用户完全透明——他们只需要解锁设备,不需要输入任何凭据。

与现有 Identity Provider 的集成

Apple 提供了标准的扩展点来连接各种 Identity Provider。你的企业 IdP 需要实现 ASAuthorizationProvider 扩展,处理 OAuth 2.0 或 SAML 令牌的交换。一旦扩展部署到设备上,所有使用 ASAuthorization API 的 App 都能自动受益。

代码片段

使用 Platform SSO 进行认证

场景:企业 App 使用系统级 SSO 进行自动登录。

import AuthenticationServices

class EnterpriseAuthManager {
    
    /// 使用 Platform SSO 进行认证
    func authenticateWithSSO() {
        // 创建 SSO Provider
        let provider = ASAuthorizationProvider()
        
        // 创建 SSO 请求
        let ssoRequest = ASAuthorizationPlatformPublicKeyCredentialProvider(
            relyingPartyIdentifier: "enterprise.example.com"
        )
        
        // 创建授权控制器
        let controller = ASAuthorizationController(authorizationRequests: [ssoRequest])
        controller.delegate = self
        controller.performRequests()
    }
}

extension EnterpriseAuthManager: ASAuthorizationControllerDelegate {
    
    func authorizationController(controller: ASAuthorizationController,
                                  didCompleteWithAuthorization authorization: ASAuthorization) {
        switch authorization.credential {
        case let credential as ASAuthorizationPlatformPublicKeyCredentialAssertion:
            // SSO 认证成功
            let token = credential.rawClientDataJSON
            print("企业 SSO 认证成功")
            // 使用令牌访问企业资源
            handleSuccessfulAuth(token: token)
            
        default:
            break
        }
    }
    
    func authorizationController(controller: ASAuthorizationController,
                                  didCompleteWithError error: Error) {
        print("企业 SSO 认证失败: \(error)")
        // 降级到传统的用户名密码登录
        fallbackToPasswordAuth()
    }
}

配置 Sign in with Apple 作为企业认证

场景:使用 Sign in with Apple 作为企业的认证方式。

import AuthenticationServices

class SignInWithAppleManager: NSObject {
    
    private var currentNonce: String?
    
    func startSignIn() {
        let nonce = randomNonceString()
        currentNonce = nonce
        
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = sha256(nonce)
        
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.performRequests()
    }
    
    // 检查用户的认证状态
    func checkCredentialState(userID: String) {
        let provider = ASAuthorizationAppleIDProvider()
        provider.getCredentialState(forUserID: userID) { state, error in
            switch state {
            case .authorized:
                // 凭据有效,用户已认证
                print("用户认证有效")
            case .revoked:
                // 用户撤销了授权,需要重新登录
                print("用户已撤销授权")
                self.handleRevokedAuth()
            case .notFound:
                // 未找到凭据
                print("未找到认证凭据")
            default:
                break
            }
        }
    }
}

extension SignInWithAppleManager: ASAuthorizationControllerDelegate {
    
    func authorizationController(controller: ASAuthorizationController,
                                  didCompleteWithAuthorization authorization: ASAuthorization) {
        guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential,
              let identityToken = credential.identityToken,
              let tokenString = String(data: identityToken, encoding: .utf8) else {
            return
        }
        
        // 将 token 发送到企业服务器验证
        verifyTokenWithServer(tokenString)
    }
    
    func authorizationController(controller: ASAuthorizationController,
                                  didCompleteWithError error: Error) {
        print("Sign in with Apple 失败: \(error)")
    }
}

通过 MDM 配置企业 SSO

场景:为企业的 MDM 部署准备 SSO 配置。

<!-- MDM 配置文件:企业 SSO 设置 -->
<!-- 通过 MDM 系统下发到所有企业设备 -->

<plist version="1.0">
<dict>
    <key>PayloadType</key>
    <string>com.apple.extensiblesso</string>
    
    <key>PayloadDisplayName</key>
    <string>企业单点登录</string>
    
    <!-- SSO 扩展配置 -->
    <key>PayloadContent</key>
    <dict>
        <!-- Identity Provider URL -->
        <key>urls</key>
        <array>
            <string>https://sso.enterprise.example.com/*</string>
            <string>https://auth.enterprise.example.com/*</string>
        </array>
        
        <!-- SSO 扩展的 Bundle Identifier -->
        <key>extensionidentifier</key>
        <string>com.enterprise.sso.extension</string>
        
        <!-- 认证类型 -->
        <key>type</key>
        <string>credential</string>
        
        <!-- 团队标识符 -->
        <key>teamidentifier</key>
        <string>ABCDE12345</string>
    </dict>
</dict>
</plist>

最佳实践

企业 IT 管理员:评估你的 Identity Provider 是否支持 Apple 的 Platform SSO。主流 IdP(Okta、Azure AD、Ping Identity)正在积极适配。规划 MDM 部署策略,先在测试设备上验证 SSO 流程,再推广到全员。

企业 App 开发者:如果你的 App 面向企业用户,集成 AuthenticationServices 框架来支持 Platform SSO。这意味着你的 App 不需要自己实现登录页面——系统会自动处理认证。配合 ASAuthorizationAppleIDProvider 的凭据状态检查来处理用户注销和授权撤销的场景。

还有什么值得关注

  • Platform SSO 的令牌存储在 Secure Enclave 中,即使设备被越狱也无法提取。
  • 企业可以通过 MDM 远程撤销设备的 SSO 令牌(比如设备丢失时)。
  • macOS Big Sur 也支持 Platform SSO,企业可以实现 iOS 和 Mac 之间的统一认证体验。
WWDC 2020