与 AWS Developer Authenticated Identities 中的登录流程逻辑混淆
Confused with logic of login flow in AWS Developer Authenticated Identities
我认为我实施开发人员身份验证的流程不正确,我一直在网上听到和做不同的事情。所以我想我会展示我的整个流程,听听这样做的正确方法是什么,并在底部提出一些问题和错误。
最初,我有一个使用密码和用户名登录的用户(我只是暂时使用 nsuserdefaults,稍后我会使用 KeyChain)。
注意:我还有一个回调,它一直向下查看我是否正确验证了用户。
登录方式:
-(void)loginBusyTimeUser:(void(^)(BOOL))callBack{
//initialize nsuserdefualts should be keychain later
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *post = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[defaults objectForKey:@"username"], @"username",
[defaults objectForKey:@"password"], @"password",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:0 error:&error];
NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:@"SOMELOGINURL"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *newJSON = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
if(!newJSON || [newJSON objectForKey:@"errorMessage"]){
NSLog(@"%@",newJSON);
callBack(false);
NSLog(@"DID NOT AUTHENTICATE");
}else{
NSLog(@"%@",newJSON);
[defaults setValue:[newJSON objectForKey:@"Token"] forKey:@"Token"];
[defaults setValue:[newJSON objectForKey:@"IdentityId"] forKey:@"IdentityId"];
[self authenticateUser:^(BOOL call){
callBack(call);
}];
}
}] resume];
}
如果一切都成功,然后我使用 AWS Cognito 和开发人员身份验证流程对我的用户进行身份验证:
-(void)authenticateUser:(void(^)(BOOL))callBack{
//Now after making sure that your user's credentials are sound, then initialize the IdentityProvider, in this case
//BusytimeAuthenticated
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
id<AWSCognitoIdentityProvider> identityProvider = [[BusytimeAuthenticated alloc] initWithRegionType:AWSRegionUSEast1
identityId:nil
identityPoolId:@"SOMEPOOLID"
logins:@{@"cognito-identity.amazonaws.com": [defaults objectForKey:@"Token"]}
providerName:@"cognito-identity.amazonaws.com"
];
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(AWSTask *task){
if([task isFaulted]){
callBack(false);
}else{
callBack(true);
}
return [defaults objectForKey:@"Token"];
}];
}
然后刷新方法会导致一些错误,所以我会显示我的 "BusytimeAuthenticated" class (.m)
//
// BusytimeAuthenticated.m
// BusyTime
//
// Created by akash kakumani on 10/14/15.
// Copyright (c) 2015 BusyTime. All rights reserved.
//
#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.
- (AWSTask *)getIdentityId {
// already cached the identity id, return it
if (self.identityId) {
return [AWSTask 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 [[AWSTask taskWithResult:nil] continueWithBlock:^id(AWSTask *task) {
if (!self.identityId) {
return [self refresh];
}
return [AWSTask taskWithResult:self.identityId];
}];
}
}
// Use the refresh method to communicate with your backend to get an
// identityId and token.
- (AWSTask *)refresh {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![self authenticatedWithProvider]) {
return [super getIdentityId];
}else{
NSDictionary *post = [[NSDictionary alloc] initWithObjectsAndKeys:
[defaults objectForKey:@"username"], @"username",
[defaults objectForKey:@"password"], @"password",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:0 error:&error];
NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:@"SOMELOGINURL"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *newJSON = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
if(!newJSON){
NSLog(@"Failure in refresh: %@",newJSON);
}else{
NSLog(@"The IdentityID in the refresh method: %@",[newJSON objectForKey:@"IdentityId" ]);
NSLog(@"The token in the refresh method: %@",[newJSON objectForKey:@"Token" ]);
self.identityId = [newJSON objectForKey:@"IdentityId" ];
self.token = [newJSON objectForKey:@"Token" ];
}
}] resume];
return [AWSTask taskWithResult:self.identityId];
}
return [AWSTask taskWithResult:self.identityId];
}
@end
我有一些问题:
是否需要 DeveloperAuthenticationClient 来解决我的问题?我看到了使用它们的示例应用程序,但我发现它们太混乱了。
我应该使用我的 ProviderName 还是应该使用 "cognito-identity.amazonaws.com"
我有时会遇到超时错误,我发现这可能是因为我的登录实现(使用 API 网关和 lambda 方法)可能存在一些冷启动问题.我解决这个问题的方法是将超时时间增加到 20 秒。这是解决这个问题的正确方法吗?
我看到在示例应用程序中,他们将 GetToken 和 Login 作为两个独立的东西使用。我认为如果我的登录名也可以用作我的 GetToken 会更容易。这合适吗?
最后,如果时间允许,请解决您在我的代码中看到的任何问题。
错误:
[Error] AWSCredentialsProvider.m line:527 |
__40-[AWSCognitoCredentialsProvider refresh]_block_invoke352 | Unable to refresh. Error is [Error
Domain=com.amazonaws.AWSCognitoCredentialsProviderErrorDomain Code=1
"identityId shouldn't be nil"
UserInfo={NSLocalizedDescription=identityId shouldn't be nil}]
(我还发现上面的错误与self.identityId没有设置有关,因为请求在一个块中,其他部分先执行,解决方案是:
- (AWSTask *)refresh {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![self authenticatedWithProvider]) {
return [super getIdentityId];
}else{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *string = [defaults objectForKey:@"IdentityId"];
self.identityId = string;
return [AWSTask taskWithResult:[defaults objectForKey:@"IdentityId"]];
}
NSString *string = [defaults objectForKey:@"IdentityId"];
return [AWSTask taskWithResult:[defaults objectForKey:@"IdentityId"]];
}
但我认为这不是正确的实施方式。 )
我相信我的代码在某个时候可以工作,但在我升级到新的 SDK 后停止工作。但是,这可能只是我最初没有注意到错误的事实。
您问题的答案:
是的,您需要有一些与后端系统通信的实体(客户端)。
您正在登录映射中使用 cognito-identity.amazonaws.com,但使用 IdentityProvider 模式进行刷新。这就是第一次身份验证成功但尝试刷新失败的原因。刷新中的逻辑永远不会触发。请查看我们的 end to end sample,了解如何实施开发人员身份验证。
据我所知,这是一种方法,但您可能会遇到性能问题。请通过他们的论坛联系 AWS Lambda 以获得更多相关指导。
我们强烈建议您遵循示例中的流程。如果您已建立信任,getToken 不需要您的身份验证凭据,而登录将始终需要身份验证凭据,因此最好不要混合使用这些凭据。
谢谢..
我认为我实施开发人员身份验证的流程不正确,我一直在网上听到和做不同的事情。所以我想我会展示我的整个流程,听听这样做的正确方法是什么,并在底部提出一些问题和错误。
最初,我有一个使用密码和用户名登录的用户(我只是暂时使用 nsuserdefaults,稍后我会使用 KeyChain)。
注意:我还有一个回调,它一直向下查看我是否正确验证了用户。
登录方式:
-(void)loginBusyTimeUser:(void(^)(BOOL))callBack{
//initialize nsuserdefualts should be keychain later
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *post = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[defaults objectForKey:@"username"], @"username",
[defaults objectForKey:@"password"], @"password",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:0 error:&error];
NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:@"SOMELOGINURL"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *newJSON = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
if(!newJSON || [newJSON objectForKey:@"errorMessage"]){
NSLog(@"%@",newJSON);
callBack(false);
NSLog(@"DID NOT AUTHENTICATE");
}else{
NSLog(@"%@",newJSON);
[defaults setValue:[newJSON objectForKey:@"Token"] forKey:@"Token"];
[defaults setValue:[newJSON objectForKey:@"IdentityId"] forKey:@"IdentityId"];
[self authenticateUser:^(BOOL call){
callBack(call);
}];
}
}] resume];
}
如果一切都成功,然后我使用 AWS Cognito 和开发人员身份验证流程对我的用户进行身份验证:
-(void)authenticateUser:(void(^)(BOOL))callBack{
//Now after making sure that your user's credentials are sound, then initialize the IdentityProvider, in this case
//BusytimeAuthenticated
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
id<AWSCognitoIdentityProvider> identityProvider = [[BusytimeAuthenticated alloc] initWithRegionType:AWSRegionUSEast1
identityId:nil
identityPoolId:@"SOMEPOOLID"
logins:@{@"cognito-identity.amazonaws.com": [defaults objectForKey:@"Token"]}
providerName:@"cognito-identity.amazonaws.com"
];
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(AWSTask *task){
if([task isFaulted]){
callBack(false);
}else{
callBack(true);
}
return [defaults objectForKey:@"Token"];
}];
}
然后刷新方法会导致一些错误,所以我会显示我的 "BusytimeAuthenticated" class (.m)
//
// BusytimeAuthenticated.m
// BusyTime
//
// Created by akash kakumani on 10/14/15.
// Copyright (c) 2015 BusyTime. All rights reserved.
//
#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.
- (AWSTask *)getIdentityId {
// already cached the identity id, return it
if (self.identityId) {
return [AWSTask 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 [[AWSTask taskWithResult:nil] continueWithBlock:^id(AWSTask *task) {
if (!self.identityId) {
return [self refresh];
}
return [AWSTask taskWithResult:self.identityId];
}];
}
}
// Use the refresh method to communicate with your backend to get an
// identityId and token.
- (AWSTask *)refresh {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![self authenticatedWithProvider]) {
return [super getIdentityId];
}else{
NSDictionary *post = [[NSDictionary alloc] initWithObjectsAndKeys:
[defaults objectForKey:@"username"], @"username",
[defaults objectForKey:@"password"], @"password",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:0 error:&error];
NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:@"SOMELOGINURL"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *newJSON = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
if(!newJSON){
NSLog(@"Failure in refresh: %@",newJSON);
}else{
NSLog(@"The IdentityID in the refresh method: %@",[newJSON objectForKey:@"IdentityId" ]);
NSLog(@"The token in the refresh method: %@",[newJSON objectForKey:@"Token" ]);
self.identityId = [newJSON objectForKey:@"IdentityId" ];
self.token = [newJSON objectForKey:@"Token" ];
}
}] resume];
return [AWSTask taskWithResult:self.identityId];
}
return [AWSTask taskWithResult:self.identityId];
}
@end
我有一些问题:
是否需要 DeveloperAuthenticationClient 来解决我的问题?我看到了使用它们的示例应用程序,但我发现它们太混乱了。
我应该使用我的 ProviderName 还是应该使用 "cognito-identity.amazonaws.com"
我有时会遇到超时错误,我发现这可能是因为我的登录实现(使用 API 网关和 lambda 方法)可能存在一些冷启动问题.我解决这个问题的方法是将超时时间增加到 20 秒。这是解决这个问题的正确方法吗?
我看到在示例应用程序中,他们将 GetToken 和 Login 作为两个独立的东西使用。我认为如果我的登录名也可以用作我的 GetToken 会更容易。这合适吗?
最后,如果时间允许,请解决您在我的代码中看到的任何问题。
错误:
[Error] AWSCredentialsProvider.m line:527 | __40-[AWSCognitoCredentialsProvider refresh]_block_invoke352 | Unable to refresh. Error is [Error Domain=com.amazonaws.AWSCognitoCredentialsProviderErrorDomain Code=1 "identityId shouldn't be nil" UserInfo={NSLocalizedDescription=identityId shouldn't be nil}]
(我还发现上面的错误与self.identityId没有设置有关,因为请求在一个块中,其他部分先执行,解决方案是:
- (AWSTask *)refresh {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![self authenticatedWithProvider]) {
return [super getIdentityId];
}else{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *string = [defaults objectForKey:@"IdentityId"];
self.identityId = string;
return [AWSTask taskWithResult:[defaults objectForKey:@"IdentityId"]];
}
NSString *string = [defaults objectForKey:@"IdentityId"];
return [AWSTask taskWithResult:[defaults objectForKey:@"IdentityId"]];
}
但我认为这不是正确的实施方式。 )
我相信我的代码在某个时候可以工作,但在我升级到新的 SDK 后停止工作。但是,这可能只是我最初没有注意到错误的事实。
您问题的答案:
是的,您需要有一些与后端系统通信的实体(客户端)。
您正在登录映射中使用 cognito-identity.amazonaws.com,但使用 IdentityProvider 模式进行刷新。这就是第一次身份验证成功但尝试刷新失败的原因。刷新中的逻辑永远不会触发。请查看我们的 end to end sample,了解如何实施开发人员身份验证。
据我所知,这是一种方法,但您可能会遇到性能问题。请通过他们的论坛联系 AWS Lambda 以获得更多相关指导。
我们强烈建议您遵循示例中的流程。如果您已建立信任,getToken 不需要您的身份验证凭据,而登录将始终需要身份验证凭据,因此最好不要混合使用这些凭据。
谢谢..