【问题标题】:Switch from unauth to developer authenticated cognito user - AWS iOS SDK从 unauth 切换到经过开发人员身份验证的 cognito 用户 - AWS iOS SDK
【发布时间】:2016-01-16 18:33:25
【问题描述】:

总体问题: 我在前端 (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

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

注意:我所做的一项重大更改是我去掉了“DeveloperAuthenticationClient”类,因为我认为没有它我也可以做到。

【问题讨论】:

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


【解决方案1】:

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

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

【讨论】:

  • 是的,你是对的,请查看我的新流程:我使用未经身份验证的凭据实例化我的用户。如果 credentialsprovider 没有设置登录: if (![credentialsProvider logins]){ 我直接调用我的后端来验证我的用户。如果一切顺利,那么我会使用经过身份验证的凭据对我的用户进行身份验证。我还为我的登录方法提供了经过身份验证的凭据的访问权限,因为它是返回 identityID 和令牌的方法。
  • 如果设置了登录名,那么我只需刷新我的 credentialsProvider
  • @user2977578 同样,您必须维护 2 个不同的身份。你正在为自己创造更多的工作。我强烈建议您不要继续走这条路。
  • 基本上unauth和auth角色都可以调用login。我首先使用 unauth 调用登录。如果可行,我将我的凭据提供程序设置为我的开发人员身份验证身份类。
  • 我会研究 api 网关,但如果它现在已经工作了,这有关系吗? 2个不同的身份,你是指unauth用户和auth用户吗?
【解决方案2】:

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

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

如果您进一步了解但开始遇到稍微不同的问题,请将此问题标记为已回答并发布单独的问题,而不是继续编辑此问题。这将有助于让事情变得清晰(这个问题/答案变得很长并且已经改变)。


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

【讨论】:

  • 当我添加它时,我得到了比以前更奇怪的错误。以前,当我调用 [credentialsProvider refresh] 时它有点工作,因为它会进入我的刷新方法。现在,当我添加它时,我收到此错误:错误:错误域 = com.amazonaws.AWSLambdaInvokerErrorDomain Code=1“操作无法完成。(com.amazonaws.AWSLambdaInvokerErrorDomain 错误 1。)”UserInfo=0x7f844d0f7ef0 {errorMessage =任务在 3.00 秒后超时,com.amazonaws.AWSLambdaInvokerFunctionErrorKey=Unhandled}
  • 等一下,让我想办法。它仍在使用 continueWithBlock 进入我的方法。
  • 这看起来像是 lambda 函数的错误。看看代码是什么,这可能会给你一个线索:docs.aws.amazon.com/AWSiOSSDK/latest/Constants/… 你也可以从 lambda 函数查看 Cloud Trails 日志记录。
  • 编辑了我的代码,现在我的 testAuth 方法(调用经过身份验证的 lambda 方法)甚至没有被调用?
  • 是的,我刚刚修复了我的 lambda 方法,我试图传入我未经身份验证的 identityId 但它没有帮助。
猜你喜欢
  • 2014-12-05
  • 2015-04-15
  • 2016-06-29
  • 2018-05-17
  • 1970-01-01
  • 2015-05-10
  • 2018-12-08
  • 2015-10-04
  • 1970-01-01
相关资源
最近更新 更多