ios - identities - create user cognito
AWS iOS SDK Cognito Developer Authentication(Swift) (2)
Creo que lo he descubierto. Necesitaba utilizar BFTask, que está diseñado para manejar tareas en segundo plano con finalización.
Para las personas que luchan con una implementación de Swift de autenticación de desarrollador con Cognito que podría tener una configuración similar a la mía, así es como lo logré:
class ExampleAppIdentityProvider: AWSAbstractCognitoIdentityProvider {
var _token: String!
var _logins: [ NSObject : AnyObject ]!
// Header stuff you may not need but I use for auth with my server
let acceptHeader = "application/vnd.exampleapp-api+json;version=1;"
let authHeader = "Token token="
let userDefaults = NSUserDefaults.standardUserDefaults()
let authToken = self.userDefaults.valueForKey("authentication_token") as String
// End point that my server gives amazon identityId and tokens to authorized users
let url = "https://api.myapp.com/api/amazon_id/"
override var token: String {
get {
return _token
}
}
override var logins: [ NSObject : AnyObject ]! {
get {
return _logins
}
set {
_logins = newValue
}
}
override func getIdentityId() -> BFTask! {
if self.identityId != nil {
return BFTask(result: self.identityId)
}else{
return BFTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
if self.identityId == nil {
return self.refresh()
}
return BFTask(result: self.identityId)
})
}
}
override func refresh() -> BFTask! {
let task = BFTaskCompletionSource()
let request = AFHTTPRequestOperationManager()
request.requestSerializer.setValue(self.acceptHeader, forHTTPHeaderField: "ACCEPT")
request.requestSerializer.setValue(self.authHeader+authToken, forHTTPHeaderField: "AUTHORIZATION")
request.GET(self.url, parameters: nil, success: { (request: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
// The following 3 lines are required as referenced here: http://stackoverflow.com/a/26741208/535363
var tmp = NSMutableDictionary()
tmp.setObject("temp", forKey: "ExampleApp")
self.logins = tmp
// Get the properties from my server response
let properties: NSDictionary = response.objectForKey("properties") as NSDictionary
let amazonId = properties.objectForKey("amazon_identity") as String
let amazonToken = properties.objectForKey("token") as String
// Set the identityId and token for the ExampleAppIdentityProvider
self.identityId = amazonId
self._token = amazonToken
task.setResult(response)
}, failure: { (request: AFHTTPRequestOperation!, error: NSError!) -> Void in
task.setError(error)
})
return task.task
}
}
Y inicializó el ExampleAppIdentityProvider
haciendo:
let identityProvider = ExampleAppIdentityProvider()
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityProvider: identityProvider, unauthRoleArn: GlobalVariables.cognitoUnauthRoleArn, authRoleArn: GlobalVariables.cognitoAuthRoleArn)
let defaultServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.bucket = GlobalVariables.awsBucket
uploadRequest.key = "/(GlobalVariables.environment)/uploads/users//(userId)//(type)//(timestamp)/original.jpg"
uploadRequest.ACL = .AuthenticatedRead
uploadRequest.body = tmpFileUrl
// Upload file
let task = transferManager.upload(uploadRequest)
GlobalVariables
una struct
llamada GlobalVariables
con variables de entorno globales que contienen valores para bucket
, unAuthRoleArn
, authRoleArn
, etc. Por supuesto que no tienes que hacer eso, pero lo estoy mencionando en caso de que alguien esté confundido.
Me está resultando difícil descifrar cómo devolver las credenciales de desarrollador proporcionadas por mi servidor (a través de AWS) a mi proveedor de identidades de ejemplo.
Parece que necesito hacer esto sincrónicamente dentro del método de refresh
en la clase ExampleIdentityProvider. Estoy usando AFNetworking para hacer la solicitud, pero es una solicitud async GET
. ¿Cómo puedo hacer esto sincrónicamente para el método de actualización en mi IdentityProvider?
Lo siguiente está en Swift:
class ExampleIdentityProvider: AWSAbstractIdentityProvider {
var newToken: String!
override var token: String {
get {
return newToken
}
set {
newToken = newValue
}
}
override func getIdentityId() -> BFTask! {
if self.identityId != nil {
return BFTask(result: self.identityId)
}else{
return BFTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
if self.identityId == nil {
return self.refresh()
}
return BFTask(result: self.identityId)
})
}
}
override func refresh() -> BFTask! {
return BFTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
let result = AFNETWORKING REQUEST FOR CREDENTIALS TO MY SERVER
self.identityId = result.identityId
self.token = result.token
return BFTask(result: self.identityId)
})
}
}
puedes generar tu clase personalizada para la autenticación cognito
import AWSS3
import AWSCore
import Alamofire
//This variable is store aws credential token
var cachedLogin : NSDictionary?
final class AmazonIdentityProvider : AWSCognitoCredentialsProviderHelper{
// Handles getting the login
override func logins() -> AWSTask<NSDictionary> {
guard let cachedLoginObj = cachedLogin else {
return getCredentials().continueWith(block: { (credentialTask) -> AWSTask<NSDictionary> in
guard let credential = credentialTask.result else {
return AWSTask(result: nil)
}
self.setCognitoTokenKey(credential: credential)
return AWSTask(result: cachedLogin)
}) as! AWSTask<NSDictionary>
}
return AWSTask(result: cachedLoginObj)
}
// Handles getting a token from the server
override func token() -> AWSTask<NSString> {
return getCredentials().continueWith(block: { (credentialTask) -> AWSTask<NSString> in
guard let credential = credentialTask.result else {
return AWSTask(result: nil)
}
self.setCognitoTokenKey(credential: credential)
return AWSTask(result: credential.token as NSString)
}) as! AWSTask<NSString>
}
// Handles getting the identity id
override func getIdentityId() -> AWSTask<NSString> {
return getCredentials().continueWith(block: { (credentialTask) -> AWSTask<NSString> in
guard let credential = credentialTask.result else {
return AWSTask(result: nil)
}
self.setCognitoTokenKey(credential: credential)
return AWSTask(result: credential.identityId as NSString)
}) as! AWSTask<NSString>
}
//This method is used to AWS Token set
func setCognitoTokenKey(credential : AmazonCognitoCredential){
let login: NSDictionary = ["cognito-identity.amazonaws.com": credential.token]
cachedLogin = login
self.identityId = credential.identityId
}
// Gets credentials from server
func getCredentials() -> AWSTask<AmazonCognitoCredential> {
let tokenRequest = AWSTaskCompletionSource<AmazonCognitoCredential>()
getAwsToken { (isSuccess, error, credentials) in
if isSuccess
{
tokenRequest.set(result: credentials)
}
else
{
tokenRequest.set(error: error!)
}
}
return tokenRequest.task
}
typealias CompletionBlock = (_ success:Bool,_ errorMassage:Error?,_ responce:AmazonCognitoCredential?) -> Void
func getAwsToken(complitionBlock : @escaping CompletionBlock) {
//Your server token code
}
/// AmazonCognito credential custom class
final class AmazonCognitoCredential {
let token: String
let identityId: String
init(token: String, identityId: String) {
self.token = token
self.identityId = identityId
}
}
y puedes usar el delegado de la aplicación
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
AWSDDLog.sharedInstance.logLevel = .all
let identityProvider = AmazonIdentityProvider()
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, unauthRoleArn: CognitoRoleUnauth, authRoleArn: CognitoRoleAuth, identityProvider: identityProvider)
let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let task = identityProvider.getIdentityId()
task.continueWith { (task:AWSTask) -> Any? in
if (task.error != nil ) {
print("/(String(describing: task.error))")
} else {
print("Task result: /(String(describing: task.result))")
}
return nil
}
return true
}