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

时间:2015-10-18 10:45:47

标签: ios authentication amazon-web-services aws-lambda amazon-cognito

整体问题: 我在前端(iOS)使用开发人员身份验证身份时遇到问题。我知道我的后端会产生正确的令牌和身份ID,但我的刷新方法永远不会被调用。我也查看了样本,但我对所发生的一切感到有些困惑。 流程说明: 目前我有一个登录屏幕,其中有一个登录按钮。用户按下登录按钮,然后我的api类获取凭据,加密密码并将其存储在钥匙串中(暂时注释掉,因为它在模拟器上不起作用)。我的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

摘要问题: 不幸的是,当我测试我的新priveleges时,我从错误中看到:“Unauth_Role / CognitoIdentityCredentials无权执行:lambda:InvokeFunction”。显然我没有正确切换。我在刷新方法中放置了一个断点,看它是否被调用。不是。我不太了解我如何正确切换。任何帮助我们开展此工作都非常感激。

注意:我做过的一个重大改变是我拿出了“DeveloperAuthenticationClient”类,因为我认为没有它我就能做到。

2 个答案:

答案 0 :(得分:1)

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

我强烈建议您在Lambda函数前设置API Gateway以删除此循环依赖项。

答案 1 :(得分:0)

根据问题中的新信息进行更新... 这里有几件事: 1.避免像while(!finished)这样的代码等待异步任务完成。在最好的情况下,这种忙碌的等待将消耗100%的CPU /核心,同时不做任何有用的事情并对电池寿命产生不利影响,只会损害应用程序的性能。而是使用带有块的通知。由于您在此实例中已经有AWSTask,而不是在nil的末尾返回[credentialsProvider refresh] continueWithBlock...,只需在此处调用您的[self testAuth]并取消已完成/代码。 2.在getIdentityId实现中,第一个if条件检查是否存在identityId,如果,则返回nil。我在这里猜测你的目标是在成功验证后缓存identityId并返回,这样你就不必在每次调用getIdentityId时调用你的后端。如果是这种情况,请确保您要返回identityId而不是nil 3.我不认为这是您的问题的原因,但会简化操作:只要您在控制台中使用Auth / UnAuth角色配置了您的身份池,您就不必在初始化AWSCognitoCredentialsProvider时明确使用它们。

如果您继续遇到问题,请解决这些问题,请更详细地调试代码,并告诉我们以下内容: 刷新方法是否被调用?如果是这样,if语句的哪些部分会输入,结果是什么?是否曾进入else块并致电您的后端身份提供商?它是否成功检索到身份ID并将其返回?

如果您越走越远但开始遇到稍微不同的问题,请将此问题标记为已回答并发布单独的问题,而不是继续编辑此问题。这将有助于保持清晰(这个问题/答案变得非常长并且已经改变)。

初始发布的问题/代码的原始答​​案... getIdentity method of the AWSCognitoCredentialsProvider返回AWSTask(即BFTask)。因此,您需要调用continueWithBlock之类的内容才能实际执行该方法。在上面的第一段代码中,您似乎并没有这样做。