2016-05-10 3 views
2

Я создаю приложение iOS (Swift), используя AWS в качестве сервера с аутентифицированными удостоверениями разработчика. Все работает нормально, пока я не закрою приложение, оставлю его на некоторое время, а затем перезапустим. В этом случае я часто, но не всегда, получаю ошибки ExpiredTokenException при попытке получить данные из AWS.AWS ExpiredTokenException после перезагрузки приложения

Вот мой код:

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 
    } 
} 

И в 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 
} 

Это post предполагает, что маркер Cognito истек, и это до разработчика для обновления вручную. Это кажется слишком сложным, так как это требует установки таймера для регулярного обновления, обработки закрытий приложений и повторных запусков и обработки запросов AWS, которые происходят во время обновления. Есть ли более простой способ? Например, возможно ли, чтобы AWS SDK автоматически вызывал обновление при попытке запросить сервер с использованием истекшего токена?

Любая помощь будет оценена по достоинству. Я использую версию 2.3.5 для AWS SDK для iOS.

ответ

1

AWS Mobile SDK для iOS 2.4.x имеет новый протокол под названием AWSIdentityProviderManager. Он имеет следующий метод:

/** 
* 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; 

Ответственность объекта, соответствующего этому протоколу должен возвратить допустимый logins словарь всякий раз, когда он запрашивается. Поскольку этот метод является асинхронным, вы можете сделать сетевые вызовы в нем, если истек кешированный токен. Реализация зависит от вас, но во многих случаях AWSIdentityProviderManager управляет несколькими AWSIdentityProvider s, объединяет их и возвращает словарь logins.

+0

спасибо @YosukeMatsuda. Вместо этого я решил реализовать пулы пользователей. Однако я изо всех сил пытаюсь получить эту работу и разместил связанный с ней вопрос [здесь] (http://stackoverflow.com/questions/37176334/aws-cognito-user-pools-in-ios-swift-app). – Elliot

0

К сожалению, разработчики, освежающие токен, являются единственным способом.

Я согласен с тем, что разработчикам приложений было бы проще, если бы AWS SDK справился с этим, но способ разработки CrdentialsProvider должен быть общим для всех поставщиков. Например, если кто-то хочет использовать Facebook в качестве провайдера, тогда AWS SDK не сможет самостоятельно обрабатывать обновление, а разработчик будет обрабатывать это в своем приложении. Сохранение потока обновления из SDK дает нам возможность сохранить общий доступ к CredentialsProvider.

+0

спасибо. Правильно ли я понимаю, что это токен Cognito, срок действия которого истек, а не токен OpenId? Если это так, не мог ли поставщик учетных данных обнаружить, что токен Cognito истек, и вызывается refresh() автоматически? Не будет ли это работать, даже если Facebook будет предоставлять токен OpenId? – Elliot

+0

«Знак Cognito» - это токен, разработанный Cognito, когда вы вызываете GetOpenIdTokenForDeveloperIdentity API со своего конца. Для CredentialsProvider этот токен эквивалентен токен доступа FB. –