版本记录
版本号 | 时间 |
---|---|
V1.0 | 2021.04.01 星期四 |
前言
Authentication Services
框架为用户提供了授权身份认证Authentication
服务,使用户更容易登录App
和服务。下面我们就一起来看一下这个框架。感兴趣的看下面几篇文章。
1. Authentication Services框架详细解析 (一) —— 基本概览(一)
2. Authentication Services框架详细解析 (二) —— 使用Sign in with Apple实现用户身份验证(一)
3. Authentication Services框架详细解析 (三) —— 密码的自动填充(一)
Overview
自动透明地将帐户转换为
Sign in with Apple
或使用强密码来提高安全性。
如果帐户的密码很弱且容易猜到,或者帐户遭到破坏,则iOS安全建议(iOS Security Recommendations)
可以帮助用户更新帐户密码。 向您的应用程序添加Account Authentication Modification Extension
,使用户可以轻松地切换为复杂的强密码,或升级为Sign in with Apple
。 用户的体验既简单又轻松,通常只需要轻按一下按钮即可。
您可以将扩展程序配置为支持升级为强密码,和升级为Sign in with Apple
或两者都有。 用户从以下位置启动升级:
- 在
Settings > Passwords
中,在查看安全建议时。 - 在您的应用中,当用户使用弱密码或不安全密码登录帐户时。
- 在您的应用中,使用专用界面来实现。
如果您的帐户安全策略需要其他步骤(例如两因素身份验证),则您的扩展程序可以在升级过程中包括这些步骤。
Configure an Associated Domain
要升级存储在iOS密码管理器中的用户帐户,您必须首先在您的应用程序和该帐户所属的域之间建立关联。 要建立此关联,请向您的网站添加一个包含Webcredential
条目的关联域文件,然后配置一个匹配的Associated Domains Entitlement。 有关如何配置关联域的更多信息,请参见Supporting Associated Domains。
Add an Account Authentication Modification Extension to Your App
Xcode提供了创建扩展的起点。 要将Authentication Modification extension
添加到您的项目中,请执行以下操作:
- 1) 在Xcode中打开您的应用程序项目,然后选择
File > New > Target
。 - 2) 从
Application Extension
组中,选择Account Authentication
,然后单击Next
。 - 3) 输入您的扩展名。
- 4) 单击
Finish
。
Declare Supported Upgrade Types
扩展程序的Info.plist
文件指定了您的应用支持的升级类型。 要支持将弱密码升级为强密码,请将ASAccountAuthenticationModificationSupportsStrongPasswordUpgrade
密钥设置为YES
。 若要支持将帐户从使用密码升级为使用Sign in with Apple
,请将ASAccountAuthenticationModificationSupportsUpgradeToSignInWithApple
设置为YES。
当系统开始强密码升级时,它将生成一个新的强密码。 如果系统生成的密码不符合您的需求,则可以选择添加ASAccountAuthenticationModificationPasswordGenerationRequirements
密钥,该密钥具有描述您的需求的字符串值。 有关此字符串的格式的详细信息,请参阅Customizing Password AutoFill Rules。 使用 Password Rules Validation Tool来验证系统根据您的要求生成的密码。
Support Automatic Strong Password Upgrades
当用户启动强密码升级时,系统将调用您的扩展以执行升级。 要一键式自动升级到强密码,系统将加载您的扩展并实例化ASAccountAuthenticationModificationViewController
的子类。 系统调用您在视图控制器中实现的changePasswordWithoutUserInteractionForServiceIdentifier:existingCredential:newPassword:userInfo:
方法。
class AccountAuthenticationModificationViewController: ASAccountAuthenticationModificationViewController {
override func changePasswordWithoutUserInteraction(
for serviceIdentifier: ASCredentialServiceIdentifier,
existingCredential: ASPasswordCredential,
newPassword: String,
userInfo: [AnyHashable : Any]?)
{
// Verify with your server that the user is authorized to
// update the password.
// Once confirmed, send the user data to your server.
}
}
此方法接收以下参数:
- 1)
ASCredentialServiceIdentifier
,用于标识要升级的服务,例如网站帐户。 - 2)服务端的当前密码。
- 3)系统生成的强密码,如果指定,则符合
ASAccountAuthenticationModificationPasswordGenerationRequirements
。 - 4)如果您的应用程序发起请求,则该用户信息词典包含特定于应用程序的信息。
要执行自动升级,extension
将与您的服务器通信以授权并执行升级。使用应用程序中的当前密码,现有token
或凭据信息,与服务器确认用户已获得执行密码升级的权限。服务器确认用户授权后,将新密码发送到服务器以执行升级。如果系统生成的密码不满足服务器的要求,则可以使用与系统提供的密码不同的密码。
在服务器上完成密码更改后,请在视图控制器的extensionContext
上调用completeChangePasswordRequestWithUpdatedCredential:userInfo :
,以传递该服务的新凭据(credential)
。系统将新凭证存储在钥匙串中,并删除旧凭据`。
let newCredential = ASPasswordCredential(
user: existingCredential.user,
password: newPassword
)
self.extensionContext.completeChangePasswordRequest(updatedCredential: newCredential)
如果用户无权执行升级,或者更新失败,请按以下步骤取消请求:
let error = ASExtensionError(.failed)
self.extensionContext.cancelRequest(withError: error)
要向用户显示自定义错误消息,请使用ASExtensionErrorCodeFailed
初始化ASExtensionError
并指定错误字符串,如下所示:
let error = ASExtensionError(.failed, userInfo: [
ASExtensionLocalizedFailureReasonErrorKey: "Authentication failed."
])
self.extensionContext.cancelRequest(withError: error)
Support Automatic Upgrades to Sign in with Apple
实施使用Sign in with Apple
自动升级的步骤与升级为强密码的步骤非常相似。要支持升级到使用Apple登录(Sign in with Apple)
,您的应用程序必须支持使用Sign in with Apple
。有关更多信息,请参阅Sign in with Apple
和Implementing User Authentication with Sign in with Apple。
当用户启动升级以使用Sign in with Apple
时,系统会加载您的扩展程序,并调用视图控制器的convertAccountToSignInWithAppleWithoutUserInteractionForServiceIdentifier:existingCredential:userInfo:
方法。
此方法接收以下参数:
- 1) 一个
ASCredentialServiceIdentifier
,用于标识要更新的服务,例如网站帐户。 - 2) 服务的当前密码。
- 3) 如果您的应用程序发起请求,则该用户信息词典包含特定于应用程序的信息。
使用当前密码向服务器授权用户可以执行升级。如果不是,则使请求失败,如上所述。
要执行升级,请通过调用getSignInWithAppleUpgradeAuthorizationWithState:nonce:completionHandler:
从extensionContext
请求Sign in with Apple
凭据。如果系统提供了Sign in with Apple
凭据,请将凭据信息发送到您的服务器,然后通过调用completeUpgradeToSignInWithAppleWithUserInfo:
完成请求。完成后,系统会从钥匙串中删除旧密码。
let myState: String = ...
let myNonce: String = ...
self.extensionContext.getSignInWithAppleUpgradeAuthorization(
state: myState,
nonce: myNonce
) { appleIDCredential, error in
guard let appleIDCredential = appleIDCredential else {
self.extensionContext.cancelRequest(
withError: ASExtensionError(.failed)
)
return
}
// Verify with your server that the user is authorized to
// convert the account to Sign in with Apple.
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
// Once confirmed, send the user data to your server.
self.extensionContext.completeUpgradeToSignInWithApple()
}
要创建Sign in with Apple
凭据,系统会提示用户并与Apple
通信。 如果用户取消了请求,则系统将调用错误指定ASExtensionErrorCodeUserCanceled
代码的completion handler
。 在这种情况下,请使用相同的错误码且没有失败原因来取消请求,并且不显示任何其他用户界面。 如果设备无法与Apple
的服务器通信,则可以为completion handler
传证书为nil
。 在这种情况下,请通过将ASExtensionErrorCodeFailed
指定为错误代码的错误来取消请求。
Perform Upgrades With Additional Security Requirements
如果用户启动帐户身份验证升级,但是您需要其他安全步骤(例如,使用两因素身份验证),则初始自动请求将失败,并显示一个error
,该错误指示需要用户交互。
let error = ASExtensionError(.userInteractionRequired)
self.extensionContext.cancelRequest(withError: error)
系统会根据原始请求的类型,通过调用prepareInterfaceToChangePasswordForServiceIdentifier:existingCredential:newPassword:userInfo:
或prepareInterfaceToConvertAccountToSignInWithAppleForServiceIdentifier:existingCredential:userInfo:
来发起包含视图控制器视图的新请求。为请求配置适当的视图控制器视图,然后从方法中返回。
方法返回后,系统会使用系统提供的导航栏(包括“取消”按钮)为视图控制器的视图提供视图。系统呈现视图后,指导用户执行其他步骤。用户完成这些步骤后,请继续升级过程。要进行强密码升级,请将原始请求中提供的新的强密码提交到您的服务器。要升级为Sign in with Apple
,请调用getSignInWithAppleUpgradeAuthorizationWithState:nonce:completionHandler:
来请求新的Sign in with Apple
的凭据,如前所述。
如果用户未能完成其他步骤,或者由于任何其他原因导致升级失败,请按照前面的示例中所述,调用cancelRequestWithError:
取消请求。系统关闭视图控制器的视图。
如果用户点击系统提供的“取消”按钮,系统将关闭该界面并调用您的视图控制器的cancelRequest
方法。如果您需要执行任何清理工作,请重写此方法并调用超类cancelRequest
方法以完成该过程。
Initiate Security Upgrades From Within Your App
要启动对强密码的升级,或者要在您的应用程序中使用Sign in with Apple
,请使用ASAccountAuthenticationModificationController
类。
当您的应用发起升级请求时,您的extension
所做的工作与前面的部分所述相同。要配置请求,请实例化ASAccountAuthenticationModificationUpgradePasswordToStrongPasswordRequest
或ASAccountAuthenticationModificationReplacePasswordWithSignInWithAppleRequest
对象,并传递以下参数:
- 用户帐户的用户名。
-
ASCredentialServiceIdentifier
,用于标识要更新的服务,例如网站帐户。 - 用户信息字典,其中包含扩展所需的任何身份验证信息。
与系统启动的升级不同,您的扩展程序在调用changePasswordWithoutUserInteractionForServiceIdentifier:existingCredential:newPassword:userInfo:
或convertAccountToSignInWithAppleWithoutUserInteractionForServiceIdentifier:existingCredential:userInfo:
的调用中不会收到现有密码。如果您的扩展程序需要现有的密码或身份验证信息来对服务器执行授权,则将其包括在用户信息字典中。
要执行请求:
- 1) 实例化一个
ASAccountAuthenticationModificationController
对象。 - 2) 将控制器的委托属性设置为遵循
ASAccountAuthenticationModificationControllerDelegate
协议的对象。 - 3) 将控制器的
presentationContextProvider
属性设置为符合ASAccountAuthenticationModificationControllerPresentationContextProviding
协议的对象。 - 4) 在控制器上调用
performRequest:
以发起请求。
以下示例显示了如何配置和启动升级到强密码的请求:
let username = "jappleseed"
let serviceIdentifier = ASCredentialServiceIdentifier(
identifier: "myservice.example.com",
type: .domain
)
let userInfo = ["com.example.authTokenKey": authToken]
let upgradeRequest = ASAccountAuthenticationModificationUpgradePasswordToStrongPasswordRequest(
user: username,
serviceIdentifier: serviceIdentifier,
userInfo: userInfo
)
let requestController = ASAccountAuthenticationModificationController()
requestController.delegate = self
requestController.presentationContextProvider = self
requestController.perform(upgradeRequest)
对于升级到Sign in with Apple
,过程是相同的,除了您实例化了一个ASAccountAuthenticationModificationReplacePasswordWithSignInWithAppleRequest
对象:
let upgradeRequest = ASAccountAuthenticationModificationReplacePasswordWithSignInWithAppleRequest(
user: username,
serviceIdentifier: serviceIdentifier,
userInfo: userInfo
)
请求完成后,根据升级结果,控制器将调用accountAuthenticationModificationController:didSuccessfullyCompleteRequest:withUserInfo:
或accountAuthenticationModificationController:didFailRequest:withError:
。 相应地将结果通知用户。
后记
本篇主要讲述了使用
Account Authentication Modification Extension
提升账号安全,感兴趣的给个赞或者关注~~~