AWS Cognito sign in not working (Swift-iOS)

妖精的绣舞 提交于 2019-12-03 20:56:41

The AWS documentation is quite confusing. After much trial and error, I was able to successfully set up Cognito, sign up, authenticate on log in, and un-authenticate on sign out. To be quite honest, I don't fully understand why I call certain things. To the best of my ability, I will explain here.

Here's how Cognito works.. First it assumes that the user is already logged in and authenticated. It checks to see if this is true. This is the reason why the entry point for your storyboard is the view controller that users see after they are logged in. This is all done with the code that runs in your AppDelegate on launch. More on what you need to fix in that below.

If the user is not logged in, startPasswordAuthentication() will be called. In your code, (as it should be) this defined in the extension of AppDelegate for the protocol AWSCognitoIdentityInteractiveAuthenticationDelegate. Furthermore, startPasswordAuthentication() is called every time the user needs to log in. If the user is already logged in once the app starts, this is not called.

Another note on your question - getDetails is only called on launch if the user is not signed in. If on launch the user is not signed in, then this is called. It is also called if you are signed in and then you sign out.

So make sure the entry point for your storyboard is the logged-in screen.

On the statement that follows I am not entirely sure, so feel free to correct me if so: AWS automatically accesses the entry point upon successful log-in. Everything you are going in your @objc func loginUser() looks correct to me. That's what I have. But make sure your entry point is not the log-in screen but rather what shows after successful log in. Here is a picture of my storyboard:

Try adding the following. I am not quite sure why exactly this works, but it results in proper authentication:

In your AppDelegate, right after your variable for the storyboard, add a boolean isInitialized as such:

     var isInitialized : Bool = false

Then add this code after you set up your Cognito configuration. (right before your return statement in didFinishLaunchingWithOptions) :

    let didFinishLaunching = AWSSignInManager.sharedInstance().interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)

    if (!self.isInitialized) {
        AWSSignInManager.sharedInstance().resumeSession(completionHandler: { (result: Any?, error: Error?) in
            print("Result: \(String(describing: result)) \n Error:\(String(describing: error))")
        })
        self.isInitialized = true
    }

Now replace the return statement you currently have for didFinishLaunching with the following:

    return didFinishLaunching

Make sure you have this delegate set in your viewDidLoad() method for your login screen (Note you have to import AWSAuthCore):

   AWSSignInManager.sharedInstance().delegate = self

and implement the protocol in your log-in VC as such:

   extension LoginViewController : AWSSignInDelegate {
       func onLogin(signInProvider: AWSSignInProvider, result: Any?, error: Error?) {
           if error == nil {

           }
       }
   }

Add these variables as class variables to your view controller that users see after they are logged in. They are referenced below.

var user : AWSCognitoIdentityUser?
var userAttributes : [AWSCognitoIdentityProviderAttributeType]?

Finally, make sure that you are checking the user attributes in the initial screen in viewWillAppear(). For example call the function fetchUserAttributes in this method:

func fetchUserAttributes() {
    self.user = AppDelegate.defaultUserPool().currentUser()
    self.user?.getDetails().continueOnSuccessWith(block: { [weak self = self] (task) -> Any? in

        AWSSignInManager.sharedInstance().resumeSession(completionHandler: { (result: Any?, error: Error?) in
            print("Result: \(String(describing: result)) \n Error:\(String(describing: error))")
        })
        guard task.result != nil else {
            // alert error
            return nil
        }
        self?.username = self?.user?.username
        self?.userAttributes = task.result?.userAttributes
        self?.userAttributes?.forEach({ (attribute) in
            print("Name: " + attribute.name!)
        })
        DispatchQueue.main.async {
                self?.setAttributeValues()
            }
        }
        return nil
    })
}

func resetAttributeValues() {
        self.user = nil
        self.userAttributes = nil
}

Finally, here is my code for signing out:

    let comp = { [weak self = self] (_ result: Any?, _ error: Error?) -> Void in
        if error == nil {
            self?.user?.signOut()
            self?.resetAttributeValues()
            self?.fetchUserAttributes()
        }
    }
    AWSSignInManager.sharedInstance().logout(completionHandler: comp)

I hope this helps. I understand this is really confusing, and to be honest, I was quite confused just writing this.. Good luck and feel free to message me with any questions.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!