Authentication Services框架详细解析 (四) —— 使用Account Authentication Modification Extension提升账号安全(一)

版本记录

版本号 时间
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 AppleImplementing 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所做的工作与前面的部分所述相同。要配置请求,请实例化ASAccountAuthenticationModificationUpgradePasswordToStrongPasswordRequestASAccountAuthenticationModificationReplacePasswordWithSignInWithAppleRequest对象,并传递以下参数:

  • 用户帐户的用户名。
  • 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提升账号安全,感兴趣的给个赞或者关注~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容