Appsync return 使用 Cognito 连接时出现 401 错误

Appsync return 401 errors when connecting with cognito

所以我设置了 cognito 和 appsync,并将它们都连接到我的 iOS 客户端。 Appsync 在控制台上运行良好,但是当我从 iOS 发出任何请求时,我收到 401 错误,没有任何错误消息。我可以正常登录和退出 Cognito。我想我可能将错误的东西传递给了某些东西?

这是我的应用委托代码: 导入 UIKit 导入 AWSAppSync 导入AWSS3 导入 AWSCognitoIdentityProvider

var credentialsProvider: AWSCognitoCredentialsProvider?
var pool: AWSCognitoIdentityUserPool?

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var storyboard: UIStoryboard? {
        return UIStoryboard(name: "Main", bundle: nil)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        AWSDDLog.sharedInstance.logLevel = .verbose
        AWSDDLog.add(AWSDDTTYLogger.sharedInstance)
        let configuration = AWSServiceConfiguration(region: AWSRegion, credentialsProvider: nil)

        let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoAppId, clientSecret: nil, poolId: CognitoPoolId)

        AWSCognitoIdentityUserPool.register(with: configuration, userPoolConfiguration: poolConfiguration, forKey: CognitoIdentityPoolId)

        pool = AWSCognitoIdentityUserPool(forKey: CognitoIdentityPoolId)

        NSLog("cognito pool username: \(pool?.currentUser()?.username ?? "unknown")")
        pool!.delegate = self

        credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegion, identityPoolId: CognitoIdentityPoolId, identityProviderManager: pool!)

        let databaseURL = URL(fileURLWithPath:NSTemporaryDirectory()).appendingPathComponent(database_name)

        do {
            // Initialize the AWS AppSync configuration
            let appSyncConfig = try AWSAppSyncClientConfiguration(url: AppSyncEndpointURL, serviceRegion: AWSRegion,
                                                                  credentialsProvider: credentialsProvider!,
                                                                  databaseURL:databaseURL)

            // Initialize the AppSync client
            appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig)

            // Set id as the cache key for objects
            appSyncClient?.apolloClient?.cacheKeyForObject = { [=11=]["id"] }
        }
        catch {
            NSLog("Error initializing appsync client. \(error)")
        }

        return true
    }

}

extension AppDelegate: AWSCognitoIdentityInteractiveAuthenticationDelegate {

    func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
        let tabController = self.window?.rootViewController as! UITabBarController


        let loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController


        DispatchQueue.main.async {
            tabController.present(loginViewController, animated: true, completion: nil)
        }

        return loginViewController
    }
}

这是我遇到的错误:

Error body: {
  "errors" : [ {
    "message" : "Unable to parse JWT token."
  } ]
})
errorDescription: (401 unauthorized) Did not receive a successful HTTP code.

iam 政策:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:GraphQL",
            "Resource": "*"
        }
    ]
}

IAM 信任关系:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "us-west-2:94OBSCURED"
        }
      }
    }
  ]
}

如果您需要更多详细信息,请告诉我。

好的,问题是:如果您使用上面的代码,则需要将您的应用程序同步设置为通过 IAM(而非 Cognito)进行身份验证。这还需要更改您的解析器,因为传递给身份对象的参数对于 IAM 和 Cognito 是不同的。

这很令人困惑,因为您正在使用 Cognito(用户池和联合身份用户池),但没有选择 Cognito。

A​​ppSync 初始化很棘手。所有 AWS documentation/examples 都提供了使用 IAM 或 API 密钥作为身份验证的示例。如果您在 AppSync 中将 Cognito 用户池设置为身份验证,则需要考虑两件事。

1) 创建 class 的扩展,如下所示。

extension YourClassName: AWSCognitoUserPoolsAuthProvider {
  func getLatestAuthToken() -> String {
   let pool = AWSCognitoIdentityUserPool(forKey: APP_TITLE)
   let session =  pool.currentUser()?.getSession()
   return (session?.result?.idToken?.tokenString)!
  }
}

2) 初始化 AppSync 时不要使用 credentialsProvider。相反,请使用 userPoolsAuthProvider。 userPoolsAuthProvider 的值是在步骤 1 中创建的 class。如果相同 class 或 class 名称,则可能是 self是单独的 class.

let appSyncConfig = try AWSAppSyncClientConfiguration.init(url: AppSyncEndpointURL, serviceRegion: AppSyncRegion, userPoolsAuthProvider:self, databaseURL:databaseURL)

CognitoUserPools 需要 JWT 令牌,而 IAM 需要 IdentityPoolProvider。传递 credentialsProvider 意味着告诉 AppSync 使用 IAM 作为身份验证。

在本文中,向下滚动并查看标题为 'Authentication Modes' 的部分。这为使用 AppSync 时 api 授权 iOS 项目的可用选项提供了很好的参考。我发现这很有用。

https://awslabs.github.io/aws-mobile-appsync-sdk-ios/#configuration