iOS(Swift)应用程序中的AWS Cognito用户池 [英] AWS Cognito User Pools in iOS (Swift) app

查看:155
本文介绍了iOS(Swift)应用程序中的AWS Cognito用户池的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的iOS(Swift)应用中实施新的AWS Cognito用户池,但我正在努力让登录过程正常运行。我基本上试图按照可用的示例这里

I'm trying to implement the new AWS Cognito User Pools in my iOS (Swift) app, but I'm struggling to get the sign in process to work. I am essentially trying to follow the example available here.

这是我到目前为止:

AppDelegate:

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:

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结果)。

Nothing seems to happen when I hit the log in button, although if I hit it again I get an NSInternalInconsistencyException (which I believe is because the AWSTask result has already been set).

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

Any help with this would be appreciated. I am using the AWS SDK for iOS version 2.4.1.

更新:

不是我原来问题的解决方案,但我已经能够通过使用显式登录方法而不是委托方法来使用户池工作(请参阅页面了解详情)。以下是我的SignInViewController中的代码:

Not a solution to my original problem, but I've been able to get User Pools working by using the explicit sign in method rather than the delegate method (see this page for details). Here is the code from my 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不同的区域),我创建了一个新的凭证使用用户池的提供商:

Then, to consume an AWS service (which in my case is located in a different region to Cognito) I have created a new Credentials Provider using the User Pool:

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中的这一行来解决这个问题:

One additional issue is that I was seeing this error each time I launched the app: "Could not find valid 'AWSDefaultRegionType', 'AWSCognitoRegionType', and 'AWSCognitoIdentityPoolId' values in info.plist.". This seems to be related to Fabric, which I am using to track crashes. I've solved this by changing this line in the AppDelegate:

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

到此:

Fabric.with([Crashlytics.self])

我希望这会有所帮助别人。

I hope this helps someone else.

推荐答案

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

Update 6: (and really final this time )

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

It is worth mentioning that (finally) AWS has made the AWS Mobile Hub build a very nice demo app that INCLUDES User Pools as a SignInProvider (With Google and Facebook too). The architecture is (in my opinion) excellent (they have separated Identity Management and getting credentials from Authentication) Check it out

更新5 :(和最终)

Update 5: (and final)

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

There is a fairly complete example implementation, and some documentation of how it works in this other answer.

iOS - AWS MobileHub使用开发人员验证的提供商登录

更新4:

如果您想要访问AWS服务,还有更多需要的步骤

If you want to get access to AWS services, there are more steps needed

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

It turns out that this does not get you authenticated with Cognito Federated Identities (the "logins" count on the identity browser remains at 0). To fix this you need to establish a credentialsProvider and do "credentialsProvider.getIdentityId". After that logins will show positive, and you can get services from AWS based upon your authenticated role.

如果您尝试对移动应用程序执行Authenticated和UnAuthenticated访问,然后您需要创建一个AWSAnonymousCredentialsProvider(在单独的服务配置中)。那么你自己提供了.invalidateCachedTemporaryCredentials()和self.credentialsProvider?.clearCredentials(),当你注销并使用匿名服务配置再次执行getidentityid时,你将得到一个匿名id。 (注意:我发现看起来如果你在凭证提供者上使用clearkeychain,每次用户退出时都会以新的ID开头,这可能会很快烧掉你的免费50,000 ID。)

If you are trying to do both Authenticated and UnAuthenticated access for your mobile app, then you need to create an AWSAnonymousCredentialsProvider (in a separate service configuration). Then you self.credentialsProvider?.invalidateCachedTemporaryCredentials() and self.credentialsProvider?.clearCredentials() when logging out and do the getidentityid again with the anonymous service configuration and you will get an anonymous id. (Note: I found it seemed like if you clearkeychain on the credentialsProvider it starts with a new id each time a user logs out, which could burn up your free 50,000 ids pretty quick. )

更新3:

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

Uploaded a github sample app for AWS User Pools for IOS in Swift.

https://github.com/BruceBuckland/signin

更新2:

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

I finally got AWS User Pools to work correctly in Swift

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

My problem was that each time the authentication start happened it was caused by an authentication failure in a different viewcontroller (my error). I ended up with a bunch of them running waiting for completion returns which never came and the API was "silent" (showed no errors). The API does not notice that it is being initiated multiple times ( by a different viewController each time) so it silently lets log in over and over. There is not enough of your code in the original post to see if you are having that same issue.

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

You have to be careful, the AWS sample code (in Objective-C) has two navigation controllers, and the code re-uses them. I don't like the way the sample app flashes the logged in view controller before the authentication delegate gets going and I was trying to improve that in the swift version and that caused my problem.

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

AWS User Pools API is set up to work with a storyboard or app structure that works like this:

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

1) Your app ASSUMES it is logged in, and then triggers the delegate which triggers authentication and the login screens if it is not.

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

2) In original logged in view controller pool.currentUser() is NOT enough to get the authentication going, API will only trigger the delegate when you do more (in my case user.getDetails()).

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

3) The authentication is completed through the didCompletePasswordAuthenticationStepWithError. This delegate method is called if you get an authentication (or other) error AND if you SUCCESSFULLY authenticate. In the case of successful authentication the NSError is nil, so it should be declared as NSError? in the delegate (this causes a warning). The API is beta, they will probably fix this.

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

4) One other little "gotcha", it may be obvious to you, it caught me, when you define your User Pool in the console you specify allowed apps, and each of these apps HAS DIFFERENT STRINGS for Client ID strings. ( I was just plugging the same thing into the example) which works badly (but does not report errors). The API needs some work in the reporting department. It is very Verbose when it is working, but says nothing if you pass it the wrong Client Strings. Also it seems to say nothing if you (like I did) call the API from different viewcontrollers. It was just taking each new authentication request from a different viewcontroller and saying nothing.

无论如何,它现在可以正常工作。我希望这有助于解决您的问题。

Anyway, it works now. I hope this helps resolve your issue.

更新:

我终于得到了getPasswordAuthenticationDetails来执行。

I finally got getPasswordAuthenticationDetails to execute.

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

It turns out it does not get executed until user.getDetails for the current user (even if there is no current user).

所以

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

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

will result in the getPasswordAuthenticationDetails callback getting executed on the second line.

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

It seems the AWS UserPool concept is that we write an app that assumes we have a logged in user. We get details from that user (for instance in the initial view controller) and the delegate gets kicked off if we don't have a user.

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

The AWS documentation for User Pools on IOS is missing some important concept pages. Those pages ARE included in the (otherwise parallel) Android documentation. I admit that I am still struggling (days now) with getting User Pools to work in swift, but reading the "Main Classes" and "Key Concepts" Parts of the Android documentation clarified a lot for me. I can't see why it was omitted from the IOS doc.

这篇关于iOS(Swift)应用程序中的AWS Cognito用户池的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆