iOS(Swift)应用程序中的AWS Cognito用户池

时间:2016-05-12 02:38:01

标签: ios amazon-web-services amazon-cognito

我正在尝试在我的iOS(Swift)应用中实施新的AWS Cognito用户池,但我很难让登录过程正常运行。我基本上试图遵循可用的示例here

这是我到目前为止所做的:

的AppDelegate:

class AppDelegate: UIResponder, UIApplicationDelegate, AWSCognitoIdentityInteractiveAuthenticationDelegate {
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: nil)
        AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = serviceConfiguration
        let configurationUserPool = AWSCognitoIdentityUserPoolConfiguration(
            clientId: "###",
            clientSecret: "#########",
            poolId: "###")
        AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: configurationUserPool, forKey: "UserPool")
        self.userPool = AWSCognitoIdentityUserPool(forKey: "UserPool")

        self.userPool!.delegate = self

        return true
    }

    func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let logInNavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("LogInNavigationController") as! UINavigationController

        dispatch_async(dispatch_get_main_queue(), {
            self.window?.rootViewController = logInNavigationController
        })

        let logInViewController = mainStoryboard.instantiateViewControllerWithIdentifier("LogInViewController") as! LogInViewController
        return logInViewController
    }
}

LogInViewController:

class LogInViewController: UIViewController, AWSCognitoIdentityPasswordAuthentication {
    var usernameText : String?
    var passwordAuthenticationCompletion = AWSTaskCompletionSource()

    func getPasswordAuthenticationDetails(authenticationInput: AWSCognitoIdentityPasswordAuthenticationInput, passwordAuthenticationCompletionSource: AWSTaskCompletionSource) {
        self.passwordAuthenticationCompletion = passwordAuthenticationCompletionSource

        dispatch_async(dispatch_get_main_queue(), {
            if self.usernameText == nil {
                self.usernameText = authenticationInput.lastKnownUsername
            }
        })
    }

    func didCompletePasswordAuthenticationStepWithError(error: NSError) {
        dispatch_async(dispatch_get_main_queue(), {
            let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let mainNavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("MainNavigationController") as! UINavigationController
            (UIApplication.sharedApplication().delegate as! AppDelegate).window?.rootViewController = mainNavigationController
        })
    }

    func logInButtonPressed() {
        self.passwordAuthenticationCompletion.setResult(AWSCognitoIdentityPasswordAuthenticationDetails(username: emailTextField.text, password: passwordTextField.text))
    }
}

当我点击登录按钮时似乎没有发生任何事情,但如果我再次点击它,我会得到一个NSInternalInconsistencyException(我相信这是因为已经设置了AWSTask结果)。

任何有关此的帮助将不胜感激。我使用的是适用于iOS版本2.4.1的AWS开发工具包。

更新

不是原始问题的解决方案,但我已经能够通过使用显式登录方法而不是委托方法来使用户池工作(有关详细信息,请参阅此page)。这是我的SignInViewController的代码:

class SignInViewController: UIViewController {
    @IBAction func signInButtonTouched(sender: UIButton) {
        if (emailTextField.text != nil) && (passwordTextField.text != nil) {
            let user = (UIApplication.sharedApplication().delegate as! AppDelegate).userPool!.getUser(emailTextField.text!)
            user.getSession(emailTextField.text!, password: passwordTextField.text!, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
                (task:AWSTask!) -> AnyObject! in

                if task.error == nil {
                    // user is logged in - show logged in UI
                } else {
                    // error
                }

                return nil
            })
        } else {
            // email or password not set
        }
    }
}

然后,要使用AWS服务(在我的情况下位于与Cognito不同的区域),我使用用户池创建了一个新的凭据提供程序:

let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "###", identityProviderManager: (UIApplication.sharedApplication().delegate as! AppDelegate).userPool!)
let serviceConfiguration = AWSServiceConfiguration(region: .APNortheast1, credentialsProvider: credentialsProvider)
AWSLambdaInvoker.registerLambdaInvokerWithConfiguration(serviceConfiguration, forKey: "Lambda")
let lambdaInvoker = AWSLambdaInvoker(forKey: "Lambda")

另外一个问题是我每次启动应用时都会看到此错误:“无法在info.plist中找到有效的'AWSDefaultRegionType','AWSCognitoRegionType'和'AWSCognitoIdentityPoolId'值。”这似乎与Fabric有关,我用它来跟踪崩溃。我通过更改AppDelegate中的这一行来解决这个问题:

Fabric.with([AWSCognito.self, Crashlytics.self])

到此:

Fabric.with([Crashlytics.self])

我希望这有助于其他人。

11 个答案:

答案 0 :(得分:16)

更新6 :(这次真的是最后一次)

值得一提的是(最终)AWS已经使AWS Mobile Hub构建了一个非常好的演示应用程序,其中包括用户池作为SignInProvider(也包括Google和Facebook)。该体系结构(在我看来)非常出色(它们将身份管理分开并从身份验证中获取凭据) 看看

更新5 :(和最终)

有一个相当完整的示例实现,以及它在其他答案中如何工作的一些文档。

iOS - AWS MobileHub sign in with developer authenticated provider

更新4:

如果您想要访问AWS服务,则需要执行更多步骤

事实证明,这不会让您通过Cognito Federated Identities进行身份验证("登录"身份浏览器上的计数保持为0)。要解决此问题,您需要建立一个credentialsProvider并执行" credentialsProvider.getIdentityId"。之后,登录将显示为正,并且您可以根据经过身份验证的角色从AWS获取服务。

如果您尝试对移动应用程序执行Authenticated和UnAuthenticated访问,则需要创建AWSAnonymousCredentialsProvider(在单独的服务配置中)。那么你self.credentialsProvider?.invalidateCachedTemporaryCredentials()和self.credentialsProvider?.clearCredentials()在注销时再次使用匿名服务配置执行getidentityid,你将得到一个匿名id。 (注意:我发现,如果你在凭证清单上使用clearkeychain,它会在每次用户注销时以新ID启动,这可能会很快烧掉你的免费50,000 ID。)

更新3:

在Swift上为IOS的AWS用户池上传了一个github示例应用程序。

https://github.com/BruceBuckland/signin

更新2:

我终于让AWS用户池在Swift中正常工作

我的问题是,每次身份验证开始时,都是由不同的viewcontroller中的身份验证失败引起的(我的错误)。我最终得到了一大堆正在运行的等待完成返回,这些回复从未出现过,而且API是#34;沉默" (没有显示错误)。 API没有注意到它被多次启动(每次都由不同的viewController),因此它可以无声地一遍又一遍地登录。原始帖子中没有足够的代码来查看您是否遇到同样的问题。

您必须要小心,AWS示例代码(在Objective-C中)有两个导航控制器,代码重新使用它们。我不喜欢示例应用程序在身份验证委托开始之前闪烁登录视图控制器的方式,我试图在swift版本中改进它并导致我的问题。

AWS User Pools API设置为使用如下所示的故事板或应用程序结构:

1)您的应用程序假定它已登录,然后触发触发身份验证的委托,如果不是,则触发登录屏幕。

2)在原始登录视图控制器中,pool.currentUser()不足以进行身份​​验证,API只会在您执行更多操作时触发委托(在我的情况下为user.getDetails())。

3)通过didCompletePasswordAuthenticationStepWithError完成身份验证。如果您获得身份验证(或其他)错误并且如果您已成功进行身份验证,则会调用此委托方法。在成功验证的情况下,NSError为nil,因此应将其声明为NSError?在委托中(这会导致警告)。 API是测试版,他们可能会修复此问题。

4)另外一个小小的“问题”,你可能很明显,当你在控制台中定义用户池时,你指定了允许的应用程序,并且每个应用程序都有不同的客户端ID字符串。 (我只是将相同的东西插入到示例中),这很糟糕(但不报告错误)。 API需要报告部门的一些工作。它工作时非常详细,但如果你传递了错误的客户端字符串则没有说什么。如果你(像我一样)从不同的viewcontrollers调用API,它似乎也没有说什么。它只是从不同的viewcontroller中获取每个新的身份验证请求,并且什么也没说。

无论如何,它现在有效。我希望这有助于解决您的问题。

更新

我终于得到了getPasswordAuthenticationDetails来执行。

事实证明,直到当前用户的user.getDetails才会执行它(即使没有当前用户)。

所以

let user = appDelegate.pool!.currentUser() let details = user!.getDetails()

将导致在第二行执行getPasswordAuthenticationDetails回调。

AWS UserPool概念似乎是我们编写了一个假定我们已登录用户的应用程序。我们从该用户那里获得详细信息(例如在初始视图控制器中),如果我们没有用户,代表就会被启动。

IOS上用户池的AWS文档缺少一些重要的概念页面。这些页面包含在(否则是并行的)Android文档中。我承认我仍在努力(现在几天)让用户池快速工作,但阅读"主要课程"和#34;关键概念" Android文档的部分内容为我澄清了很多。我不明白为什么它会从IOS文档中省略。

答案 1 :(得分:8)

为使用Objective-c的人和亚马逊提供的示例应用 CognitoYourUserPoolsSample 添加2美分。 @ Bruce0已经用他的快速解决方案涵盖了一切。但是如果你遇到这个问题,当你点击登录时没有调用 getPasswordAuthenticationDetails 是因为你没有在 [self.user getDetails] 上调用所有。确实 - getDetails触发getPasswordAuthenticationDetails。如果您仔细观察AWS示例应用程序,他们会在 UserDetailTableViewController 的viewDidLoad中启动应用程序时调用它,这是第一个加载的控制器。如果用户未登录,那么getDetails响应会以某种方式触发SignInViewController。这就是我将在下面解释的内容。它就像一个“myHomeViewController”类型,你想要显示用户相关的信息。否则,您希望默认显示登录/注册屏幕。

  • 作为一般经验法则,请在AppDelegate中连接并初始化Cognito用户池( didFinishLaunchingWithOptions ),就像在示例应用中一样。确保添加 AWSCognitoIdentityInteractiveAuthenticationDelegate 并实施 startPasswordAuthentication ,您将在其中启动登录ViewController。让AppDelegate处理WHAT_TO_DO_IF_USER_NOT_SIGNED_IN(例如将SignInViewController置于顶部),然后将注意力集中在应用程序中的某个地方WHEN_DOES_THE_USER_NEEDS_TO_SIGNIN。

  • 当您需要特定于用户的数据时,请告知应用程序是时候检查用户是否已登录(self.user getDetails)。同样,如果用户未登录,则AppDelegate知道该怎么做。它过度管理应用程序并在所有内容上显示登录视图。因此,它可能在开始时(例如Facebook,Twitter等)或其他地方(例如Ebay等)。只需在viewDidLoad的末尾调用 [self.user getDetails] 即可。这将阻止当前ViewController在身份验证步骤(登录/注册)之前显示,或者只是在用户已登录时加载当前的ViewController。

在您的应用中使用AWS User Pool功能时,请按照以下步骤操作:

  1. 在任何YourViewControllers
  2. 中找出您需要用户特定数据的位置
  3. 在相关的ViewDidLoad中,调用[self.user getDetails]
  4. 如果用户已登录,则使用self.user getDetails的completionHandler显示用户特定数据。
  5. 如果没有,则在AppDelegate中自动调用startPasswordAuthentication,这会在显示YourViewController之前显示登录ViewController,因为您需要特定于用户的数据
  6. 用户登录或注册
  7. 关闭登录/注册ViewController,然后返回到YourViewController,现在可以加载一些用户特定的数据。
  8. AWS示例App不是直截了当的,但它非常简单。

答案 2 :(得分:2)

谢谢艾略特。我正在尝试写几天的快速版本代码。

我尝试使用以下代码使用显式signIn。

@IBAction func signInButtonPressed(sender: AnyObject) {

var emailTextField = "username"
var passwordTextField = "password"

let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: nil)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = serviceConfiguration
let configurationUserPool = AWSCognitoIdentityUserPoolConfiguration.init(clientId: "####", clientSecret: "#####", poolId: "#####")
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: configurationUserPool, forKey: "TestUserPool")

let userPool = AWSCognitoIdentityUserPool(forKey: "TestUserPool")
let user = userPool.getUser(emailTextField)

user.getSession(emailTextField, password: passwordTextField, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
    (task:AWSTask!) -> AnyObject! in

    if task.error == nil {
            print("No Error")
            print(task.result)
    } else {
            print("Some Error")
            print(task.error)
    }
    return nil
})
}

当我提供正确的凭据时,它会转到错误块。每次运行代码时都会向我的手机发送验证码,尽管我已经在注册过程中验证了我的用户。响应机构

Response body:
{"AuthState":"H4sIAAAAAAAAAAXB3ZJzMAAA0EeqBDvTnfkulhVCpRXyI3dNmI8KzU7bLZ5+z+m3HBjINz2jp6rxB174rmT+agWweHyPLVydEqFXi2o8j9gjTT6XcH1qeA+vWWQVbAMDW6gXvhEYgHOMH3gmg06pNTP61pBaNvO1E3zvEPFaSS2+3ccuQ6qUVvXcYjqBQKFoKvfoJHgLDKJx3VhlkKsIUGs7qbhH6qXZ3a9kl+v0uPEEOWqR0/7gk4T8iiYPm0XBXt59LivPwAGUmSr1RAfDqSz8COhkZcQLFdsev3oGVw3oWTRRXIHuRkTuqYS6/juHBIYRgzTsZ1crqHB5I5OZ2JvaMmB2aKqpS2qYizMqg5KjgqI24DtNGLfXenGu8/+/zU5ZnZlVCXTRNwtKxgXP2k0LJK9T58TCnxxRJtLnQ7AAFD4lZpnWk+dY4fGBCFqZlP4YyUGfqVQ3rW/i/PgJPnd8WN8fw/Hr5D0OChfhfCleb290yaV/AXf4itllINJONfv3B7RgGQzfAQAA","CodeDeliveryDetails":    
{"DeliveryMedium":"SMS","Destination":"+*******8869"}}
Some Error
Optional(Error Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=-1000 "startMultiFactorAuthentication not implemented by authentication delegate" UserInfo={NSLocalizedDescription=startMultiFactorAuthentication not implemented by authentication delegate})

当我提供错误的密码时,响应正文

Response body:
{"__type":"NotAuthorizedException","message":"Incorrect username or password."}
Some Error
Optional(Error Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=12 "(null)" UserInfo={__type=NotAuthorizedException, message=Incorrect username or password.})

你能否在这里建议我做错了什么?

答案 3 :(得分:2)

我也遵循原始海报问题中提到的相同步骤,但应用程序从未切换到启动时的登录屏幕。我已经通过直接放在AppDelegate.application(....)方法中验证了切换视图的代码是正确的。似乎永远不会调用startPasswordAuthentication(...)delete方法。有人可以使用AWSCognitoIdentityInteractiveAuthenticationDelegate协议发布指向切换到登录屏幕的示例应用程序的链接吗?

答案 4 :(得分:1)

似乎方法" startMultiFactorAuthentication"没有在委托中实现,这就是为什么检测到错误的密码,但是当给出更正的密码时,它会升级到MFA,但是在委托中找不到启动MFA功能,因此登录失败。

答案 5 :(得分:1)

将Cognito集成到iOS中非常棘手,特别是当您是像我这样的新手时,以上答案是正确的,但是如果您仍在努力或陷入实现部分,那么此答案可能会有所帮助。

我假设其中包含 MFA或简单登录。

这就是我的CognitoUserManagerClass的样子。

 class CognitoUserManager: NSObject {

static var shared = CognitoUserManager()

var pool : AWSCognitoIdentityUserPool?

func awsConfig(){
    let configuration = AWSServiceConfiguration(region: Constants.AWSRegionName, credentialsProvider: nil)
    let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: Constants.AWSClientId,
                                                                    clientSecret: Constants.AWSClientSecret,
                                                                    poolId: Constants.AWSPoolId)
    AWSCognitoIdentityUserPool.register(with: configuration, userPoolConfiguration: poolConfiguration, forKey: "POOL_NAME")
}


func getPoolFromAWS(name: String){
    pool = AWSCognitoIdentityUserPool(forKey: name)
}

func clearDataAndSignout(){
     //This will clear all the data stored in Keychain or user session. 
    pool?.clearAll()
}

对于所有与Cognito相关的配置,我都希望使用单独的类。

一旦启动应用程序。在AppDelegate的didFinishLaunch函数中调用此函数。

    CognitoUserManager.shared.awsConfig()
    CognitoUserManager.shared.getPoolFromAWS(name: "POOL_NAME")

现在,第一步将是检查用户是否已登录?

步骤1。在didFinishLaunch之后,我调用了InitialViewController,决定根据KeyChain中的令牌将其发送到HOME SCREEN或LOGIN SCREEN。

注意:当您通过iOS中的Cognito通过任何方法成功登录时,Cognito会自行负责将令牌保存在钥匙串中。

 class InitialViewController: UIViewController {

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(true)

    CognitoUserManager.shared.pool!.currentUser()?.getSession().continueWith { task in
        if let error = task.error as NSError?{
            //Print ERROR
            self.login()
        }else{
            guard let accessToken = task.result?.accessToken?.tokenString else {
                self.login()
                return nil
            }
            self.home()
        }
        return nil
    }
  }
}

步骤2。我在登录屏幕上获取了用户电子邮件和密码,然后将其发送到OTP(MFA)屏幕,并在MFA Auth屏幕上调用getSession(带有电子邮件和密码),以避免将多个OTP发送到用户。它基于设计要求,您可以选择自己的方式。

第3步。我的MFA身份验证屏幕我正在执行所有与登录相关的Stuff的事情。

 class OTPViewController : UIViewController {


var mfaCodeCompletionSource: AWSTaskCompletionSource<NSString>?
var user: AWSCognitoIdentityUser?

override func viewDidLoad() {
    super.viewDidLoad()

    CognitoUserManager.shared.pool?.delegate = self

    guard let email = emailText, let pass = passwordText else {return}
    user = CognitoUserManager.shared.pool?.getUser(email)
    //HERE IF YOU'RE USING SIMPLE USER POOL WITH MFA THEN YOU'LL BE DIRECTED TO HOME SCREEN AND getSession() will return tokens, but if you're using MFA then it will trigger and send OTP on your Mobile.
    user?.getSession(email, password: pass, validationData: nil).continueWith(block: { (task) -> Any? in
        if let error = task.error as NSError?{
            //PRINT ERROR
        }else{
            let accessToken = task.result?.accessToken?.tokenString
            print(accessToken)
            self.sendToHome()
        }

        return nil
    })  
}

//GETTING OTP FROM TEXT FIELD AND SETTING IT.
@IBAction func SubmitOTPButtonPressed(_ sender: Any) {
    guard let otp = securtiyCodeTextfield.text else {return}
    self.mfaCodeCompletionSource?.set(result: otp as NSString)
}

}

  extension OTPViewController : AWSCognitoIdentityInteractiveAuthenticationDelegate{

func startMultiFactorAuthentication() -> AWSCognitoIdentityMultiFactorAuthentication {
    //THIS WILL CALLED IF YOU'RE USING MFA.
    return self
}

func startNewPasswordRequired() -> AWSCognitoIdentityNewPasswordRequired {
    //Called for first time to change the temporary Password.
    return self
}

func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
    return self
}

 }


  extension OTPViewController : AWSCognitoIdentityNewPasswordRequired, AWSCognitoIdentityPasswordAuthentication, AWSCognitoIdentityMultiFactorAuthentication{

func getCode(_ authenticationInput: AWSCognitoIdentityMultifactorAuthenticationInput, mfaCodeCompletionSource: AWSTaskCompletionSource<NSString>) {
    //MFA
    self.mfaCodeCompletionSource = mfaCodeCompletionSource
}

func didCompleteMultifactorAuthenticationStepWithError(_ error: Error?) {
    print(error.debugDescription)
}

func getDetails(_ authenticationInput: AWSCognitoIdentityPasswordAuthenticationInput, passwordAuthenticationCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails>) {
}

func didCompleteStepWithError(_ error: Error?) {
    print(error.debugDescription)
}

func getNewPasswordDetails(_ newPasswordRequiredInput: AWSCognitoIdentityNewPasswordRequiredInput, newPasswordRequiredCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityNewPasswordRequiredDetails>) {
    //SEND TO SETNEWPASSWORD CONTROLLER TO SET NEW PASSWORD
}
func didCompleteNewPasswordStepWithError(_ error: Error?) {
    print(error.debugDescription)
}

}

如果您认为此答案需要编辑,请继续。

答案 6 :(得分:0)

对我来说,我一直收到此错误,因为我已经验证了,但在尝试登录之前我没有验证用户。一旦验证一切正常。

答案 7 :(得分:0)

我遵循相同的例子并处理同样的问题,我还没有完全设法解决它,但我强烈怀疑这个问题与这个函数永远不会执行有关:

func getPasswordAuthenticationDetails(authenticationInput: AWSCognitoIdentityPasswordAuthenticationInput, passwordAuthenticationCompletionSource: AWSTaskCompletionSource) {
    self.passwordAuthenticationCompletion = passwordAuthenticationCompletionSource
    dispatch_async(dispatch_get_main_queue(), {() -> Void in
        if self.usernameText == nil{
            self.usernameText = authenticationInput.lastKnownUsername
        }
    })
}

我尝试在此方法中放置断点和打印语句,似乎永远不会被激活。我建议你在代码中做同样的事情,因为听起来你的问题与我的相同。我查看了示例,但无法找到手动调用方法的位置。我注意到在您的代码中,您将passwordAuthenticationCompletion的值初始化为:

var passwordAuthenticationCompletion = AWSTaskCompletionSource()

在登录方法中这一行使用相关值之前,似乎应该调用getPasswordAuthenticationDetails()self.passwordAuthenticationCompletion.setResult(AWSCognitoIdentityPasswordAuthenticationDetails(username: emailTextField.text, password: passwordTextField.text))

我已经被困了一段时间,现在试图比这更进一步,但我仍然认为这是实现用户注册/登录的正确途径。示例中的某些代码可能无法完全转换为Swift,因此一些重要的函数不会被触发。如果我确认一个解决方案,我会继续调查并更新我的答案。

答案 8 :(得分:0)

我使用Swift遵循前面提到的相同步骤,我注意到didCompletePasswordAuthenticationStepWithError从未被调用过,尽管LogInViewController扩展了AWSCognitoIdentityPasswordAuthentication

此外,即使委托也实现startPasswordAuthentication(),代理中也不会调用AWSCognitoIdentityInteractiveAuthenticationDelegate

我想知道这是否是Swift实现的问题,因为Amazon提供的示例Objective-C具有所有这些功能。

答案 9 :(得分:0)

我认为这有问题:

对象-c - &gt;

self.passwordAuthenticationCompletion.result = [[AWSCognitoIdentityPasswordAuthenticationDetails alloc] initWithUsername: username password:password]; 

Swift - &gt; self.passwordAuthenticationCompletion.setResult(AWSCognitoIdentityPasswordAuthenticationDetails.init(username: username, password: password))

并且因为前一个语句中有错误,“didCompletePasswordAuthenticationStepWithError”方法没有触发。

我尝试了许多没有运气的东西:(   - 我试图在Swift中实现所有东西(不工作)   - 我尝试将Object-C文件添加到基于Swift的项目(不是Work)

所以,我想我会使用原始样本作为我项目的首发。

<强>更新

我实现了SignInViewController&amp; Swift中的MFAController并在基于Object-C的项目中导入这些Swift文件。它工作正常! 所以,现在我确定在我们尝试实施“AWSCognitoIdentityPasswordAuthentication”&amp;&amp; amp;基于Swift的项目中的“AWSCognitoIdentityMultiFactorAuthentication”协议。 我找到的唯一解决方案是使用基于Object-c的项目。

答案 10 :(得分:0)

这就是我在Swift中实现的方式,只需一个ViewController,而且没有在AppDelegate中设置任何东西:

class LoginViewController: UIViewController, AWSCognitoIdentityInteractiveAuthenticationDelegate,  AWSCognitoIdentityPasswordAuthentication  {

        var passwordAuthenticationCompletion = AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails>()
        var pool = AWSCognitoIdentityUserPool.init(forKey: "UserPool")

        override func viewDidLoad() {
                super.viewDidLoad()
                //setup service configuration
                let serviceConfiguration = AWSServiceConfiguration.init(region: .USEast1, credentialsProvider: nil)
                //create and config a pool
                let configuration = AWSCognitoIdentityUserPoolConfiguration.init(clientId: "YourClientId", clientSecret: "YourClientId", poolId: "YourPoolId")
                AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: configuration, forKey: "UserPool")
                pool = AWSCognitoIdentityUserPool.init(forKey: "UserPool")
                pool.delegate = self
        }

        @IBAction func logInButtonPressed(sender: UIButton) {
            pool.getUser().getDetails()
        }

        func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
            return self
        }


        func getDetails(_ authenticationInput: AWSCognitoIdentityPasswordAuthenticationInput, passwordAuthenticationCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails>) {
            self.passwordAuthenticationCompletion = passwordAuthenticationCompletionSource
            let result = AWSCognitoIdentityPasswordAuthenticationDetails.init(username: "username", password: "password")
        }

}