AWS ExpiredTokenException after app relaunch

亡梦爱人 提交于 2019-12-02 06:23:01

问题


I'm building an iOS (Swift) app using AWS as the backend with Developer Authenticated Identities. Everything works fine until I close the app, leave it for a while and then relaunch. In this scenario I often, but not always, receive ExpiredTokenException errors when trying to retrieve data from AWS.

Here is my code:

class DeveloperAuthenticatedIdentityProvider: AWSAbstractCognitoIdentityProvider {
    var _token: String!
    var _logins: [ NSObject : AnyObject ]!

    override var token: String {
        get {
            return _token
        }
    }

    override var logins: [ NSObject : AnyObject ]! {
        get {
            return _logins
        }
        set {
            _logins = newValue
        }
    }

    override func getIdentityId() -> AWSTask! {
        if self.identityId != nil {
            return AWSTask(result: self.identityId)
        } else {
            return AWSTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
                if self.identityId == nil {
                    return self.refresh()
                }
                return AWSTask(result: self.identityId)
            })
        }
    }

    override func refresh() -> AWSTask! {
        let apiUrl = "https://url-goes-here"    // call my server to retrieve an OpenIdToken
        request.GET(apiUrl, parameters: nil, progress: nil,
            success: {
                (task: NSURLSessionDataTask, response: AnyObject?) -> Void in

                let tmp = NSMutableDictionary()
                tmp.setObject("temp", forKey: "ExampleApp")
                self.logins = tmp as [ NSObject : AnyObject ]

                let jsonDictionary = response as! NSDictionary
                self.identityId = jsonDictionary["identityId"] as! String
                self._token = jsonDictionary["token"] as! String
                awstask.setResult(response)
            },
            failure: {
                (task: NSURLSessionDataTask?, error: NSError) -> Void in

                awstask.setError(error)
            }
        )

        return awstask.task
    }
}

And in the AppDelegate:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    let identityProvider = DeveloperAuthenticatedIdentityProvider()

    // set default service configuration
    let credentialsProvider = AWSCognitoCredentialsProvider(regionType: cognitoRegion, identityProvider: identityProvider, unauthRoleArn: unauthRole, authRoleArn: authRole)
    let configuration = AWSServiceConfiguration(region: defaultServiceRegion, credentialsProvider: credentialsProvider)
    AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration

    // set service configuration for S3 (my bucket is located in a different region to my Cognito and Lambda service)
    let credentialsProviderForS3 = AWSCognitoCredentialsProvider(regionType: cognitoRegion, identityProvider: identityProvider, unauthRoleArn: unauthRole, authRoleArn: unauthRole)
    let awsConfigurationForS3 = AWSServiceConfiguration(region: s3ServiceRegion, credentialsProvider: credentialsProviderForS3)
    AWSS3TransferUtility.registerS3TransferUtilityWithConfiguration(awsConfigurationForS3, forKey: "S3")

    return true
}

This post suggests that the Cognito token has expired and it is up to the developer to manually refresh. This seems overly complex as it would require setting a timer to refresh regularly, handling app closures and relaunches and handling AWS requests that occur while the refresh is taking place. Is there a simpler way? For example, is it possible to have the AWS SDK automatically call refresh whenever it attempts to query the server using an expired token?

Any help would be appreciated. I'm using version 2.3.5 of the AWS SDK for iOS.


回答1:


The AWS Mobile SDK for iOS 2.4.x has a new protocol called AWSIdentityProviderManager. It has the following method:

/**
 * Each entry in logins represents a single login with an identity provider.
 * The key is the domain of the login provider (e.g. 'graph.facebook.com') and the value is the
 * OAuth/OpenId Connect token that results from an authentication with that login provider.
 */
- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins;

The responsibility of an object conforming to this protocol is to return a valid logins dictionary whenever it is requested. Because this method is asynchronous, you can make networking calls in it if the cached token is expired. The implementation is up to you, but in many cases, AWSIdentityProviderManager manages multiple AWSIdentityProviders, aggregates them and return the logins dictionary.




回答2:


Unfortunately developers refreshing the token is the only way.

I agree that it would be simpler for app developers if AWS SDK handled this but the way CrdentialsProvider is designed is supposed to be generic for all providers. For example, if someone wants to use Facebook as provider then AWS SDK will not be able to handle the refresh on its own and developer will have t handle that in his app. Keeping the refresh flow out of the SDK gives us the capability to keep the CredentialsProvider generic.



来源:https://stackoverflow.com/questions/37127831/aws-expiredtokenexception-after-app-relaunch

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