ios - 此带有用户池的身份池不支持未经身份验证的访问

标签 ios amazon-web-services amazon-cognito federated-identity

我有一个 Cognito 用户池,用于从应用程序注册/加入我的用户,然后使用 Cognito Identity 提供身份验证。我禁用了未经身份验证的用户。 用户注册后,将在池中创建用户。当他登录时,身份会在身份池中创建,我可以看到此身份已链接到用户池(链接登录)。但是,当用户尝试访问 AWS 资源(Dynamo、Lambda 函数等)时,调用返回“此身份池不支持未经身份验证的访问”。但是,我能够获取用户详细信息和在身份池中创建的身份 ID。

这是我使用的代码:

func cognitoUserPoolInit(window:UIWindow, debugLogFiles: DebugLogFiles) {
    self.window = window

    //Configure Cognito Identity User Pool. Edit ConstantAWS to change pool
    let serviceConfiguration = AWSServiceConfiguration(region: K.COGNITO_REGIONTYPE, credentialsProvider: nil)
    let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: K.COGNITO_USER_POOL_APP_CLIENT_ID, clientSecret: K.COGNITO_USER_POOL_APP_CLIENT_SECRET, poolId: K.COGNITO_USER_POOL_ID)

    AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: "UserPool")

    self.pool = AWSCognitoIdentityUserPool(forKey: "UserPool")
    self.pool!.delegate = self
    self.cognitoIdentityUser = self.pool!.currentUser()
}

func getCognitoUserPoolUserId() {
            self.cognitoIdentityUser!.getDetails().continueWithBlock() { (task) in
                dispatch_async(dispatch_get_main_queue()) {
                    self.needtoGetCognitoUserId = false
                    if task.error != nil {  // some sort of error
                        let alert = UIAlertController(title: "", message: task.error?.userInfo["message"] as? String, preferredStyle: UIAlertControllerStyle.Alert)
                        alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))

                        NSLog("Domain: " + (task.error?.domain)! + " Code: \(task.error?.code)")

                        if task.error?.code == NSURLErrorNotConnectedToInternet {
                            self.lastError = (task.error?.code)!
                            //no internet connection. Fire a timer to get our credential as soon as network is back
                            let internetOfflineTimer:NSTimer =  NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: #selector(UserPool.internetOffline), userInfo: nil, repeats: false)
                            dispatch_async(dispatch_get_main_queue(), {() -> Void in
                                NSRunLoop.mainRunLoop().addTimer(internetOfflineTimer, forMode: NSDefaultRunLoopMode)
                            })
                        } else {
                            if task.error?.userInfo["message"] != nil {
                                NSLog(task.error?.userInfo["message"] as! String)

                            }
                        }
                    } else {
                        // I got no error
                        // i got the username earlier - use it
                        self.lastError = 0
                        if let response: AWSCognitoIdentityUserGetDetailsResponse = task.result as? AWSCognitoIdentityUserGetDetailsResponse {
                            var sub: String?
                            for attribute in response.userAttributes! {
                                if attribute.name == "sub" {
                                    sub = attribute.value
                                    NSLog("sub:" + sub!)
                                    break;
                                }

                            }
                            //if the user Id, then go ahead and get the dynamoDB table
                            if sub != nil {
                                self.cognitoUserPoolUserId = sub
                                self.getCognitoIdentity()
                            } else {
                                NSLog("UserId not found in response")
                            }
                        }
                    }
                }


                return nil
            }

      }


    func getCognitoIdentity() -> Bool {
    // Initialize the Amazon Cognito credentials provider

    //get pool id from plist (Federated Identieis pool not User pool)
    var myDict: NSDictionary?
    var identityPoolID: String?
    var region: String?
    //PoolId points to TestIDPool in the Federated Identitied/West region for test purpose
    if let path = NSBundle.mainBundle().pathForResource("Info", ofType: "plist") {
        myDict = NSDictionary(contentsOfFile: path)
        identityPoolID = myDict!.objectForKey("AWS")!.objectForKey("CredentialsProvider")!.objectForKey("CognitoIdentity")!.objectForKey("Default")!.objectForKey("PoolId")! as? String;
        region = myDict!.objectForKey("AWS")!.objectForKey("CredentialsProvider")!.objectForKey("CognitoIdentity")!.objectForKey("Default")!.objectForKey("Region") as? String;
    } else {
        return false
    }

    self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: region!.aws_regionTypeValue(), identityPoolId: identityPoolID!, identityProviderManager:self.pool)
    AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: self.credentialsProvider)

    transferManager = AWSS3TransferManager.defaultS3TransferManager()


    // Retrieve your Amazon Cognito ID
    self.credentialsProvider!.getIdentityId().continueWithBlock { (task: AWSTask!) -> AnyObject! in
        if (task.error != nil) {
            print("Error: " + task.error!.localizedDescription)
        }
        else {
            // the task result will contain the identity id
            print("cognitoId: " + self.credentialsProvider!.identityId!)
            //At this point we get the identity to query the database
            self.queryLatestItem()
        }
        return nil
    }
    return true
}


func queryLatestItem() {
        let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()

        let queryExpression = AWSDynamoDBQueryExpression()
    queryExpression.scanIndexForward = false
    queryExpression.limit = 1
    queryExpression.keyConditionExpression = "userId = :UID"
    queryExpression.expressionAttributeValues = [":UID" : (self.cognitoUserPoolUserId)!]

    dynamoDBObjectMapper .query(StatisticsDB.self, expression: queryExpression) .continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: { (task:AWSTask!) -> AnyObject! in
        if (task.error != nil) {
            print("Error: \(task.error)") --> this is where i get the unauthenticated error.....
...

cognitoUserPoolInit() 在用户进入需要 DynamoDB 数据的 UI 时从 appDelegate 和 getCognitoUserPoolUserId() 调用。

如果我在联合池中选择“启用对未经身份验证的身份的访问”,它会正常工作。

此外,我有一个 Web 应用程序,可以登录、正确验证并毫无问题地访问 AWS 服务。我也是,我的 AWS/角色配置应该是好的,并且可能在应用端发生了一些错误。

我不明白如何获取用户详细信息和正确的身份 ID(来自 print("cognitoId: "+ self.credentialsProvider!.identityId!))并得到未经身份验证的错误。

再次重启应用程序会出现稍微不同的错误:

{
    Connection = "keep-alive";
    "Content-Length" = 129;
    "Content-Type" = "application/x-amz-json-1.1";
    Date = "Sun, 29 Jan 2017 20:04:06 GMT";
    "x-amzn-ErrorMessage" = "Access to Identity 'us-west-2:714eccXXXa5-42d8-8b29-5e2XXXXXXX' is forbidden.";
    "x-amzn-ErrorType" = "NotAuthorizedException:";
    "x-amzn-RequestId" = "16fc81c2-e65e-11e6-9643-756bf858abb7";
}

为我使用的 auth 添加了角色权限:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*",
                "dynamodb:*",
                "lambda:*",
                "s3:*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

和信任关系

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "us-west-2:7cXXXX5f-b91e-4fc9-a72c-6f91XXXXXXX"
        },
        "ForAnyValue:StringLike": {
          "cognito-identity.amazonaws.com:amr": "authenticated"
        }
      }
    }
  ]
}

最佳答案

我找到了根本原因。以下行将重新初始化之前设置的服务配置:

let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()

所以我将前一行替换为:

let objectMapperConfiguration = AWSDynamoDBObjectMapperConfiguration()        
serviceConfig = AWSServiceConfiguration(region: .USWest2, credentialsProvider: self.credentialsProvider)
AWSDynamoDBObjectMapper.registerDynamoDBObjectMapperWithConfiguration(serviceConfig!, objectMapperConfiguration: objectMapperConfiguration, forKey: "USWest2DynamoDBObjectMapper")

let dynamoDBObjectMapper = AWSDynamoDBObjectMapper(forKey: "USWest2DynamoDBObjectMapper")

关于ios - 此带有用户池的身份池不支持未经身份验证的访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41925319/

相关文章:

amazon-web-services - Cloudformation YAML 模板(如果其他情况未按预期工作)

javascript - AWS Cognito - 创建用户而不向他们发送验证电子邮件

ios - Objective-C 附加字符串不起作用 NSXMLParser

ios - 如何在 iOS 中为通用应用程序添加新的 XIB 文件?

c# - Xamarin 哪里是 Id 对象

javascript - 无服务器 CORS 预检请求失败 - AWS API Stripe

ios - 我可以使用Xcode 9和macOS Mojave将应用程序上传到iOS AppStore吗?

node.js - 无法在 dynamodb-local 中创建表 - aws

oauth-2.0 - 这是否可以使用 cognito 的授权代码授权类型作为 api-gateway 中的授权方?

ruby-on-rails - 上传到 Amazon S3 并从 Rails 服务器调用 Amazon Cognito 身份