AWS iOS SDK Cognito 开发人员身份验证 (Swift)

Posted

技术标签:

【中文标题】AWS iOS SDK Cognito 开发人员身份验证 (Swift)【英文标题】:AWS iOS SDK Cognito Developer Authentication (Swift) 【发布时间】:2015-04-15 04:23:33 【问题描述】:

我很难弄清楚如何将我的服务器(通过 AWS)提供的开发人员凭据返回给我的示例身份提供商。

看来我需要在 ExampleIdentityProvider 类的 refresh 方法中同步执行此操作。我正在使用 AFNetworking 发出请求,但它是异步 GET 请求。如何为我的 IdentityProvider 上的刷新方法同步执行此操作?

以下是在 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)
        )
    

【问题讨论】:

【参考方案1】:

我相信我已经弄明白了。我需要使用 BFTask,它是为处理后台任务而构建的。

对于那些在使用 Cognito 进行开发人员身份验证的 Swift 实现中苦苦挣扎的人,他们可能与我有类似的设置,这就是我完成它的方式:

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://***.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
    

并通过以下方式初始化ExampleAppIdentityProvider

    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)

我创建了一个名为 GlobalVariablesstruct,其中包含保存 bucketunAuthRoleArnauthRoleArn 等值的全局环境变量。当然你不必这样做,但我提及它以防有人感到困惑。

【讨论】:

您能展示一下您是如何初始化提供程序/配置以供 AWS 使用的吗? @user871177 查看上面的更新代码。希望对您有所帮助。 能不能不用 AWSTask 来代替单独导入 Bolts 框架? @JBaczuk 这是在亚马逊将 AWSTask 包含在此框架中之前编写的,而是使用 BFTask。您现在当然可以使用 AWSTask。 当你设置的登录映射值是“temp”任意?即使我成功获得令牌并设置登录映射,我似乎也无法获得经过身份验证的身份。 (docs.aws.amazon.com/cognito/devguide/identity/…)【参考方案2】:

您可以为 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
    

你可以在应用委托中使用

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

【讨论】:

【参考方案3】:

首先要将文件、图像、视频上传到 AWS S3 privet 存储桶,您需要为您需要的 ('CognitoId, 进行 AWS 身份验证 >CognitoAccesstoken),您从后端服务器获得。您应该具有“CognitoPoolID”、“S3 存储桶名称”和“Region >' 您可以将其保存在 swift 代码中的常量文件中。 之后,您必须为 AWS 身份验证编写 单独的类

import UIKit
import AWSCore
// this custom class is dedicated for getting getting aws dev auth identity credentials
class DeveloperAuthenticatedIdentityProvider: AWSCognitoCredentialsProviderHelper 
    override init(regionType: AWSRegionType, identityPoolId: String, useEnhancedFlow: Bool, identityProviderManager: AWSIdentityProviderManager?) 
        super.init(regionType: regionType, identityPoolId: identityPoolId, useEnhancedFlow: useEnhancedFlow, identityProviderManager: identityProviderManager)
    
    override func token() -> AWSTask<NSString> 
        self.identityId = “ADD_COGNITO_IDENTITY_ID”
        let token = “ADD_COGNITO_ACCESS_TOKEN”
        return AWSTask(result: token )
    
    override func logins () -> AWSTask<NSDictionary> 
        return super.logins()
    
    /*
     * Use the refresh method to communicate with your backend to get an
     * identityId and token.
     */
    func refresh() -> AWSTask<NSString> 
        self.identityId = “ADD_COGNITO_IDENTITY_ID”
        return AWSTask(result: identityID)
    
     

//从您上传文件的类中编写以下代码

let devAuth = DeveloperAuthenticatedIdentityProvider.init(
    regionType: ADD_REGION,
                identityPoolId:”ADD_COGNITO_POOL_ID”,
                            useEnhancedFlow: true,
                                        identityProviderManager: nil)
let credentialsProvider = AWSCognitoCredentialsProvider.init(regionType:”ADD_REGION”, identityProvider: devAuth)
let configuration = AWSServiceConfiguration.init(region:”ADD_REGION”, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration


@IBAction func uplaodVideo()
    uploadFile(with: "FILE_NAME", type: "mov")

func uploadFile(with resource: String, type: String) 
        let key = "\(resource).\(type)"
        let localImagePath = Bundle.main.path(forResource: resource, ofType: type)
        let localImageUrl = URL(fileURLWithPath: localImagePath!)
        let transferManager1 = AWSS3TransferUtility.default()
        let expression = AWSS3TransferUtilityUploadExpression()
        self.uploadCompletionHandler =  (task, error) -> Void in
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: 
                if ((error) != nil)
                    print("Failed with error")
                    print("Error: \(error!)");
                
                else
                    print("Sucess")
                
            )
        
        let transferUtility = AWSS3TransferUtility.default()
        transferUtility.uploadFile(localImageUrl, bucket: "", key: key, contentType: "video/mov", expression: expression, completionHandler: uploadCompletionHandler).continueWith  (task) -> AnyObject? in
            if let error = task.error 
                print("Error: \(error.localizedDescription)")
            
            if let _ = task.result 
                print("Upload Starting!")
            
            return nil;
        
    

【讨论】:

以上是关于AWS iOS SDK Cognito 开发人员身份验证 (Swift)的主要内容,如果未能解决你的问题,请参考以下文章

如何在iOS中使用AWSMobileClient获取AWS Cognito用户属性?

是否可以使用iOS SDK更改Amazon Cognito中的用户名?

什么是用于在 Cognito 中登录的 AWS 开发工具包库(从后端不使用 Amplify)?

AWS Cognito:生成令牌并在使用 amazon-cognito-identity-js SDK 刷新后

AWS iOS SDK,服务配置为`nil

如何配置 AWS 用户 cognito 身份验证流程以在 Java sdk 后端生成身份令牌、访问令牌?