从 unauth 切换到经过开发人员身份验证的 cognito 用户 - AWS iOS SDK

Switch from unauth to developer authenticated cognito user - AWS iOS SDK

总体问题: 我在前端使用开发人员身份验证时遇到问题 (iOS)。我知道我的后端会生成正确的令牌和 identityID,但我的刷新方法从未被调用过。我也看过样本,但我对发生的一切感到有点困惑。 流程说明: 目前我有一个带有登录按钮的登录屏幕。用户按下登录按钮,然后我的 api class 获取凭据,加密密码并将其存储在钥匙串中(现在已注释掉,因为它在模拟器上不起作用)。我的 DeveloperAuthenticatedIdentityProvider 称为我的应用程序 BusytimeAuthenticated。我已经完成了所有方法(我正在使用 AWS lambda 和 DynamoDB 对用户进行身份验证)我从未经身份验证的访问开始,它只允许我访问两种方法,即登录和注册。然后我想假设我的身份验证用户允许我调用我的其他方法。

我的API代码:

[AWSLogger defaultLogger].logLevel = AWSLogLevelVerbose;
id<AWSCognitoIdentityProvider> identityProvider = [[BusytimeAuthenticated alloc] initWithRegionType:AWSRegionUSEast1
                                                                                                          identityId:nil
                                                                                identityPoolId:@"SOMEIDENTITYPOOLID"
                                                                                logins:@{@"SOMEPROVIDERNAME": @"SOMEUSERNAME"}
                                                                                       providerName:@"SOMEPROVIDERNAME"
                                                                                                          ];

credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1
                                                                    identityProvider:identityProvider
                                                                       unauthRoleArn:nil
                                                                         authRoleArn:nil];

configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1
                                                                     credentialsProvider:self.credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
[[credentialsProvider refresh] continueWithBlock:^id(BFTask *task){
    [self testAuth];
    return nil;
}];

我的 DeveloperAuthenticatedIdentityProvider 代码(BusytimeAuthenticated):

#import "BusytimeAuthenticated.h"

@interface BusytimeAuthenticated()
@property (strong, atomic) NSString *providerName;
@property (strong, atomic) NSString *token;
@end

@implementation BusytimeAuthenticated
@synthesize providerName=_providerName;
@synthesize token=_token;



- (instancetype)initWithRegionType:(AWSRegionType)regionType
                        identityId:(NSString *)identityId
                    identityPoolId:(NSString *)identityPoolId
                            logins:(NSDictionary *)logins
                      providerName:(NSString *)providerName{
    if (self = [super initWithRegionType:regionType identityId:identityId accountId:nil identityPoolId:identityPoolId logins:logins]) {
        self.providerName = providerName;
    }
    return self;
}

// Return the developer provider name which you choose while setting up the
// identity pool in the Amazon Cognito Console

- (BOOL)authenticatedWithProvider {
    return [self.logins objectForKey:self.providerName] != nil;
}


// If the app has a valid identityId return it, otherwise get a valid
// identityId from your backend.

- (BFTask *)getIdentityId {
    // already cached the identity id, return it
    if (self.identityId) {
        return [BFTask taskWithResult:nil];
    }
    // not authenticated with our developer provider
    else if (![self authenticatedWithProvider]) {
        return [super getIdentityId];

    }
    // authenticated with our developer provider, use refresh logic to get id/token pair
    else {
        return [[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
            if (!self.identityId) {
                return [self refresh];
            }
            return [BFTask taskWithResult:self.identityId];
        }];
    }

}


// Use the refresh method to communicate with your backend to get an
// identityId and token.

- (BFTask *)refresh {
    if (![self authenticatedWithProvider]) {
        return [super getIdentityId];
    }else{
//        KeychainWrapper *keychain = [[KeychainWrapper alloc]init];
        AWSLambdaInvoker *lambdaInvoker = [AWSLambdaInvoker defaultLambdaInvoker];
        NSDictionary *parameters = @{@"username" : @"SOMEUSERNAME",
                                     @"password":@"SOMEENCRYPTEDPASS",
                                     @"isError" : @NO};
        NSLog(@"Here");
        [[lambdaInvoker invokeFunction:@"login" JSONObject:parameters] continueWithBlock:^id(BFTask* task) {
            if (task.error) {
                NSLog(@"Error: %@", task.error);
            }
            if (task.exception) {
                NSLog(@"Exception: %@", task.exception);
            }
            if (task.result) {
                self.identityId = [task.result objectForKey:@"IdentityId" ];
                self.token = [task.result objectForKey:@"Token" ];
//                [keychain mySetObject:[task.result objectForKey:@"Token" ] forKey:@"Token"];
//                [keychain mySetObject:[task.result objectForKey:@"IdentityId" ] forKey:@"IdentityId"];
                NSLog(@"Result: %@", task.result);

            }
            return [BFTask taskWithResult:self.identityId];
        }];



    }
    return NULL;
}

@end

问题总结: 不幸的是,当我测试我的新权限时,我从错误中看到:"Unauth_Role/CognitoIdentityCredentials is not authorized to perform: lambda:InvokeFunction"。显然我没有正确切换。我在我的刷新方法中放置了一个断点,以查看它是否被调用。不是。我不太了解如何正确切换。非常感谢任何帮助让它工作的帮助。

注意:虽然我确实做了一个很大的改变,但我去掉了 "DeveloperAuthenticationClient" class 因为我认为没有它我也能做到。

根据问题中的新信息进行更新... 这里有几件事: 1. 避免像 while(!finished) 这样的代码等待异步任务完成。在最好的情况下,这种忙碌等待的方式将在 100% 时消耗 CPU/core 而无用,并且会对电池寿命产生不利影响,并且只会损害应用程序的性能。相反,使用带有块的通知。因为在这种情况下你已经有了一个 AWSTask,而不是在 [credentialsProvider refresh] continueWithBlock... 的末尾 returning nil 只需在那里调用你的 [self testAuth] 并做去掉 finished/while 代码。 2. 在你的 getIdentityId 实现中,第一个 if 条件检查是否有 identityId,如果有 ,它是 returns nil。我猜你的目标是在成功验证后缓存 identityId 和 return 这样你就不必在每次调用 getIdentityId 时都调用你的后端。如果是这样的话,很确定你想要 return identityId 而不是 nil 3. 我不认为这是你的问题的原因,但会简化事情:只要你在控制台中配置了具有 Auth/UnAuth 角色的身份池,你就不必在以下情况下显式使用它们初始化 AWSCognitoCredentialsProvider.

一旦这些问题得到解决,如果您仍然遇到问题,请更详细地调试代码并告诉我们如下内容: 刷新方法是否被调用?如果是这样,它进入了你的 if 语句的哪些部分,结果是什么?它是否曾经进入 else 块并调用您的后端身份提供者?它是否成功检索到身份 ID 并 return 它?

如果您更进一步,但开始遇到稍微不同的问题,那么请将此问题标记为已回答,并 post 标记为单独的问题,而不是继续编辑此问题。这将有助于保持清晰(这个 question/answer 变得很长并且已经更改)。


初始 posted question/code... 的原始答案 getIdentity method of the AWSCognitoCredentialsProvider returns an AWSTask (i.e. a BFTask). So you'll need to call something like continueWithBlock 以便实际执行该方法。在上面的第一段代码中,您似乎没有这样做。

根本问题是您正在尝试调用 Lambda 函数(需要凭据)来获取凭据。因为您使用的是 "default" 客户端配置,所以当您的经过开发人员身份验证的客户端返回响应时,它将覆盖用于访问您的 Lambda 函数的凭据。此外,一旦该 id 已转换为经过身份验证,您将无法使用它在未经身份验证的流程中获取凭据,并且需要生成一个新的未经身份验证的 id 才能再次进行身份验证,然后返回到您经过身份验证的 id。

强烈建议您在 Lambda 函数前设置 API Gateway 以消除这种循环依赖。