I want to retrieve basic information like name, email from Google account. Here Get User information after successful authentication with Oauth2 I've found tip to change the property "shouldFetchGoogleUserProfile" to YES, but it's not accessible for me.
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope
clientID:kMyClientID
clientSecret:kMyClientSecret
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
// error - can't access property "shouldFetchGoogleUserProfile"
viewController.signIn.shouldFetchGoogleUserProfile = YES;
[[self navigationController] pushViewController: viewController
animated:YES];
I cannot also get the result after sign-in
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (!error) {
// userProfile - not accessible
// NSDictionary *profile = viewController.signIn.userProfile;
} else {
NSLog(#"Failure %#", error);
}
}
I had this same issue. Add
#import "GTL/GTMOAuth2SignIn.h"
to the bridging header which is the class for signIn.
Related
I'm trying to get my Cognito login to work.
The problem is that it's not working and I'm not getting error messages from AWS, or XCode. I've implemented it according to the tutorial and the AWS sample code (maybe wrongly?). I've tried to understand how the code works by adding a couple of NSlog's within the AWS cognito functions so that I know whether they get excecuted, but they do not show up in my console either. Why are these function not being run without even sending an error? Is there something obvious that I'm forgetting?
Here's the essential parts of my code
// loginviewcontroller.h
#import AWSCognitoIdentityProvider;
#interface LoginViewController : UIViewController <AWSCognitoIdentityPasswordAuthentication>
#property (nonatomic, strong) NSString * usernameText;
#end
loginviewcontroller.m file:
// loginviewcontroller.m
#property (nonatomic, strong) AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails*> *passwordAuthenticationCompletion;
- (IBAction)signInPressed:(UIButton *)sender {
self.passwordAuthenticationCompletion.result = [[AWSCognitoIdentityPasswordAuthenticationDetails alloc] initWithUsername:self.userName.text password:self.password.text];
NSLog(#"button pressed");};
-(void) getPasswordAuthenticationDetails: (AWSCognitoIdentityPasswordAuthenticationInput *) authenticationInput passwordAuthenticationCompletionSource: (AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails *> *) passwordAuthenticationCompletionSource {
//keep a handle to the completion, you'll need it continue once you get the inputs from the end user
self.passwordAuthenticationCompletion = passwordAuthenticationCompletionSource;}
-(void) didCompletePasswordAuthenticationStepWithError:(NSError*) error {
NSLog(#"didCompletePasswordAuthenticationStepWithError");
dispatch_async(dispatch_get_main_queue(), ^{
//present error to end user
if(error){
NSLog(#"Error");
[[[UIAlertView alloc] initWithTitle:error.userInfo[#"__type"]
message:error.userInfo[#"message"]
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil] show];
}else{
NSLog(#"Success");
//dismiss view controller
[self dismissViewControllerAnimated:YES completion:nil];
}
});
appdelegate.h
//appdelegate.h
#import AWSCognitoIdentityProvider;
#interface AppDelegate : UIResponder <UIApplicationDelegate, AWSCognitoIdentityInteractiveAuthenticationDelegate>
#property(nonatomic,strong) LoginViewController* LoginViewController;
appdelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//setup AWS service config
AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:nil];
//create a pool
AWSCognitoIdentityUserPoolConfiguration *configuration = [[AWSCognitoIdentityUserPoolConfiguration alloc] initWithClientId:#"xxxxxx" clientSecret:#"xxxxxxx" poolId:#"us-east-1_xxxxxx"];
[AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithConfiguration:serviceConfiguration userPoolConfiguration:configuration forKey:#"us-east-1_xxxxx"];
AWSCognitoIdentityUserPool *pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:#"us-east-1_xxxxxx"];
pool.delegate = self;
return YES;
}
-(id<AWSCognitoIdentityPasswordAuthentication>) startPasswordAuthentication{
//implement code to instantiate and display login UI here
//return something that implements the AWSCognitoIdentityPasswordAuthentication protocol
NSLog(#"startpasswordauth AWS!");
return self.LoginViewController;
}
Also I did not understand this property line that's in the AWS github sample. The notation of *xxx I haven't see before. Here's the line:
#property (nonatomic, strong) AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails*> *passwordAuthenticationCompletion;
It's not mentioned in the tutorial, but without it
self.passwordAuthenticationCompletion.result = [[AWSCognitoIdentityPasswordAuthenticationDetails alloc] initWithUsername:self.userName.text password:self.password.text];
errors that the attribute is not found.
I have also tried this but delegate methods are not working.
Secondly, I tried with this code:
[AWSServiceManager.defaultServiceManager.defaultServiceConfiguration.credentialsProvider invalidateCachedTemporaryCredentials];
AWSCognitoIdentityUserPool *pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:#"User"];
AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
self.user = [delegate.pool currentUser];
[[ self.user getSession:_userName.text password:_txtPassword.text validationData:nil ] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
//success, task.result has user session
dispatch_async(dispatch_get_main_queue(), ^{
if(task.error || task.isCancelled) {
[[[UIAlertView alloc] initWithTitle:task.error.userInfo[#"__type"]
message:task.error.userInfo[#"message"]
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil] show];
}else {
AWSCognitoIdentityUserSession *session = (AWSCognitoIdentityUserSession *) task.result;
NSString *tokenStr = [session.idToken tokenString];
[[NSUserDefaults standardUserDefaults]setObject:tokenStr forKey:#"token"];
[[NSUserDefaults standardUserDefaults]synchronize];
[self performSelectorOnMainThread:#selector(pushToDashbard) withObject:nil waitUntilDone:YES];
}});
return nil;
}]
If I am passing the right credentials then this is giving the token, with wrong credentials giving no error response.
In my main view controller, when a button is pressed I run the following code:
if (![PFUser currentUser]) { // No user logged in
// Create the log in view controller
CustomSignUp *logInViewController = [[CustomSignUp alloc] init];
[logInViewController setDelegate:self]; // Set ourselves as the delegate
// Create the sign up view controller
self.signUpViewController = [[TheActualSignUp alloc] init];
[self.signUpViewController setDelegate:self]; // Set ourselves as the delegate
self.signUpViewController.fields = (PFSignUpFieldsUsernameAndPassword
| PFSignUpFieldsSignUpButton
| PFSignUpFieldsEmail
| PFSignUpFieldsAdditional
| PFSignUpFieldsDismissButton);
[self.signUpViewController.signUpView.additionalField setPlaceholder:#"First & Last Name"];
[logInViewController setSignUpController:self.signUpViewController];
logInViewController.facebookPermissions = #[ #"email", #"public_profile", #"user_friends" ];
logInViewController.fields = (PFLogInFieldsUsernameAndPassword
| PFLogInFieldsFacebook
| PFLogInFieldsTwitter
| PFLogInFieldsLogInButton
| PFLogInFieldsSignUpButton
| PFLogInFieldsPasswordForgotten);
// Present the log in view controller
[self.navigationController pushViewController:logInViewController animated:YES];
}
The view controller for a login screen shows up, and I can successfully log in an already created user. However, when I try to sign up someone, I run into issues. The sign up window appears fine, and I type in all the codes, but when I click the button to send the info in to sign it up, nothing happens. Here is the code (in the same view controller). Would greatly appreciate any help on this. Am using Parse on Buddy.com. None of the NSLogs are getting called when signing up.
- (BOOL)logInViewController:(PFLogInViewController *)logInController shouldBeginLogInWithUsername:(NSString *)username password:(NSString *)password {
// Check if both fields are completed
if (username && password && username.length != 0 && password.length != 0) {
return YES; // Begin login process
}
[[[UIAlertView alloc] initWithTitle:#"Missing Information"
message:#"Make sure you fill out all of the information!"
delegate:nil
cancelButtonTitle:#"ok"
otherButtonTitles:nil] show];
return NO; // Interrupt login process
}
// Sent to the delegate when a PFUser is logged in.
- (void)logInViewController:(PFLogInViewController *)logInController didLogInUser:(PFUser *)user {
PFUser *me = [PFUser currentUser];
NSLog(#"Regular Login");
[self dismissViewControllerAnimated:YES completion:NULL];
}
- (void)logInViewController:(PFLogInViewController *)logInController didFailToLogInWithError:(NSError *)error {
NSLog(#"Failed to log in...%#", error);
}
// Sent to the delegate when the log in screen is dismissed.
- (void)logInViewControllerDidCancelLogIn:(PFLogInViewController *)logInController {
[self.navigationController popViewControllerAnimated:YES];
}
- (BOOL)signUpViewController:(PFSignUpViewController *)signUpController shouldBeginSignUp:(NSDictionary *)info {
NSLog(#"Signup");
BOOL informationComplete = YES;
// loop through all of the submitted data
for (id key in info) {
NSString *field = [info objectForKey:key];
if (!field || field.length == 0 || ![signUpController.signUpView.additionalField.text containsString:#" "] ) { // check completion
informationComplete = NO;
break;
}
}
// Display an alert if a field wasn't completed
if (!informationComplete) {
[[[UIAlertView alloc] initWithTitle:#"Missing Information"
message:#"Make sure you fill out all of the information, including first & last name!"
delegate:nil
cancelButtonTitle:#"ok"
otherButtonTitles:nil] show];
}
return informationComplete;
}
- (void)signUpViewController:(PFSignUpViewController *)signUpController didSignUpUser:(PFUser *)user {
NSLog(#"Signed them up");
[user saveEventually];
[self dismissViewControllerAnimated:YES completion:nil]; // Dismiss the PFSignUpViewController
}
// Sent to the delegate when the sign up attempt fails.
- (void)signUpViewController:(PFSignUpViewController *)signUpController didFailToSignUpWithError:(NSError *)error {
NSLog(#"Failed to sign up...");
}
// Sent to the delegate when the sign up screen is dismissed.
- (void)signUpViewControllerDidCancelSignUp:(PFSignUpViewController *)signUpController {
NSLog(#"User dismissed the signUpViewController");
}
Looking through your code, it's not immediately obvious as to what the problem is. If you ping Parse on Buddy's customer support at support#buddy.com, we can help.
I am trying to access the gmail messages in offline access mode. gmail access token I get from the server end.
I followed this link to here
I created my own authenticator class and subclass from GTMOAuth2Authentication and implemented the protocol as mentioned in the above link.
The canAutherize always fail and even though I make gmail query, It crashes in authorize function. Any help would be appreciated.
- (void)viewDidLoad {
[super viewDidLoad];
if ([self.subjectInfo length] > 0) {
[self.subjectLabel setText:self.subjectInfo];
}else {
[self.subjectLabel setText:#""];
}
self.service = [[GTLServiceGmail alloc] init];
[self fetchAccessToken];
// Initialize the Gmail API service & load existing credentials from the keychain if available.
}
// When the view appears, ensure that the Gmail API service is authorized, and perform API calls.
- (void)viewDidAppear:(BOOL)animated {
if (!self.service.authorizer.canAuthorize) {
// Not yet authorized, request authorization by pushing the login UI onto the UI stack.
// [self presentViewController:[self createAuthController] animated:YES completion:nil];
[self fetchAccessToken];
} else {
[self fetchMail:[self gmailMsgId]];
}
}
-(void) fetchAccessToken
{
[[APIManager sharedManager] fetchGmailToken:^(NSDictionary *resultDict) {
if (resultDict != nil) {
self.accessToken = [resultDict objectForKey:#"access_token"];
_authInst = [[GmailAuthenticator alloc] initWithAccessToken:self.accessToken];
self.service.authorizer = _authInst;
}
} failure:^(NSError *error) {
NSLog(#"fail to fetch access token");
}];
}
- (void)fetchMail:(NSString*)messageId {
GTLQueryGmail *query = [GTLQueryGmail queryForUsersMessagesGet];
query.messageId = messageId;
[self.service executeQuery:query
delegate:self
didFinishSelector:#selector(displayResultWithTicket:finishedWithObject:error:)];
}
- (void)displayResultWithTicket:(GTLServiceTicket *)ticket
finishedWithObject:(GTLGmailMessage *)messageResponse
error:(NSError *)error {
if (error == nil) {
NSLog(#"description is %#", [messageResponse description]);
} else {
NSLog(#"error : %#", [error description]);
}
}
I need to integrate GMail inbox in my application after authentication.So how can I query the inbox content of GMail by using the API. And also I have to access the other features too.So Please help me to find the exact swift code to access the GMail.
Using Google Docs iOS Quickstart:
Step 1: Turn on the Gmail API
Step 2: Prepare the workspace
Step 3: Set up the sample
Here is a sample code, replace the contents of the ViewController.h file with the following code:
#import <UIKit/UIKit.h>
#import "GTMOAuth2ViewControllerTouch.h"
#import "GTLGmail.h"
#interface ViewController : UIViewController
#property (nonatomic, strong) GTLServiceGmail *service;
#property (nonatomic, strong) UITextView *output;
#end
Replace the contents of ViewController.m with the following code:
#import "ViewController.h"
static NSString *const kKeychainItemName = #"Gmail API";
static NSString *const kClientID = #"YOUR_CLIENT_ID_HERE";
#implementation ViewController
#synthesize service = _service;
#synthesize output = _output;
// When the view loads, create necessary subviews, and initialize the Gmail API service.
- (void)viewDidLoad {
[super viewDidLoad];
// Create a UITextView to display output.
self.output = [[UITextView alloc] initWithFrame:self.view.bounds];
self.output.editable = false;
self.output.contentInset = UIEdgeInsetsMake(20.0, 0.0, 20.0, 0.0);
self.output.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.output];
// Initialize the Gmail API service & load existing credentials from the keychain if available.
self.service = [[GTLServiceGmail alloc] init];
self.service.authorizer =
[GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:kClientID
clientSecret:nil];
}
// When the view appears, ensure that the Gmail API service is authorized, and perform API calls.
- (void)viewDidAppear:(BOOL)animated {
if (!self.service.authorizer.canAuthorize) {
// Not yet authorized, request authorization by pushing the login UI onto the UI stack.
[self presentViewController:[self createAuthController] animated:YES completion:nil];
} else {
[self fetchLabels];
}
}
// Construct a query and get a list of labels from the user's gmail. Display the
// label name in the UITextView
- (void)fetchLabels {
self.output.text = #"Getting labels...";
GTLQueryGmail *query = [GTLQueryGmail queryForUsersLabelsList];
[self.service executeQuery:query
delegate:self
didFinishSelector:#selector(displayResultWithTicket:finishedWithObject:error:)];
}
- (void)displayResultWithTicket:(GTLServiceTicket *)ticket
finishedWithObject:(GTLGmailListLabelsResponse *)labelsResponse
error:(NSError *)error {
if (error == nil) {
NSMutableString *labelString = [[NSMutableString alloc] init];
if (labelsResponse.labels.count > 0) {
[labelString appendString:#"Labels:\n"];
for (GTLGmailLabel *label in labelsResponse.labels) {
[labelString appendFormat:#"%#\n", label.name];
}
} else {
[labelString appendString:#"No labels found."];
}
self.output.text = labelString;
} else {
[self showAlert:#"Error" message:error.localizedDescription];
}
}
// Creates the auth controller for authorizing access to Gmail API.
- (GTMOAuth2ViewControllerTouch *)createAuthController {
GTMOAuth2ViewControllerTouch *authController;
// If modifying these scopes, delete your previously saved credentials by
// resetting the iOS simulator or uninstall the app.
NSArray *scopes = [NSArray arrayWithObjects:kGTLAuthScopeGmailReadonly, nil];
authController = [[GTMOAuth2ViewControllerTouch alloc]
initWithScope:[scopes componentsJoinedByString:#" "]
clientID:kClientID
clientSecret:nil
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
return authController;
}
// Handle completion of the authorization process, and update the Gmail API
// with the new credentials.
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)authResult
error:(NSError *)error {
if (error != nil) {
[self showAlert:#"Authentication Error" message:error.localizedDescription];
self.service.authorizer = nil;
}
else {
self.service.authorizer = authResult;
[self dismissViewControllerAnimated:YES completion:nil];
}
}
// Helper for showing an alert
- (void)showAlert:(NSString *)title message:(NSString *)message {
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
#end
Step 4: Run the sample
Notes: Authorization information is stored in your Keychain, so subsequent executions will not prompt for authorization.
You can review and learn more about iOS and Google API(GMAIL API) in https://developers.google.com/gmail/api/v1/reference/ to apply other feature you want to add.
I hope this helps :)
Hey Folks i have a problem with authentication for the login credentials of my app. I currently have a rails web service running from my localhost, that features a main login screen for a admin user with password credentials to display functions.
The problem is that i am creating a RESTful iOS application running alongside my rails app, that just takes these JSON requests and bypasses them.
All i want is to create a way for me to enter admin and password without having to use auth_token? it seems to be the only way to do it, to simply authenticate the admin user first in the keychain. Im using the framework AFNetowrking for authentication.SSKeychain a wrapper for accounts, and SVProgressHUD for lightweight huds
.I also have the JSON and XML requests being logged in the i terminal but failing due to not being able to connect to the server with this error
error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo=0x7556d50 {NSErrorFailingURLStringKey=http://localhost:3000.json/, NSErrorFailingURLKey=http://localhost:3000.json/, NSLocalizedDescription=Could not connect to the server., NSUnderlyingError=0xeb805c0 "Could not connect to the server."}
this is how im storing the credentials for the authClient, all want to do is specify the same info used to log-into the web service client which is.
username:admin and password:taliesin
but unsure how to do this?
these are what i have so for the AuthAPIClient, CredentialsStore and LoginViewController
update if anybody knows a easier way to do this please can you let me know, will be much appreciated.
AuthAPIClient.m
#import "AuthAPIClient.h"
#import "CredentialStore.h"
#define BASE_URL #"http://admin:taliesin#localhost:3000"
#implementation AuthAPIClient
+ (id)sharedClient {
static AuthAPIClient *__instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURL *baseUrl = [NSURL URLWithString:BASE_URL];
__instance = [[AuthAPIClient alloc] initWithBaseURL:baseUrl];
});
return __instance;
}
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setAuthTokenHeader];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(tokenChanged:)
name:#"token-changed"
object:nil];
}
return self;
}
- (void)setAuthTokenHeader {
CredentialStore *store = [[CredentialStore alloc] init];
NSString *authToken = [store authToken];
[self setDefaultHeader:#"auth_token" value:authToken];
}
- (void)tokenChanged:(NSNotification *)notification {
[self setAuthTokenHeader];
}
#end
CredentialStore.m
#import "CredentialStore.h"
#import "SSKeychain.h"
#define SERVICE_NAME #"http://admin:taliesin#localhost:3000"
#define AUTH_TOKEN_KEY #"auth_token"
#implementation CredentialStore
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSString *user = [NSString stringWithFormat:#"%c%s%#", 'a', "a", #"a"];
NSString *password = [NSString stringWithFormat:#"%c%s%#", 'a', "a", #"a"];
NSURLCredential *credential = [NSURLCredential credentialWithUser:user
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
- (BOOL)isLoggedIn {
return [self authToken] != nil;
}
- (void)clearSavedCredentials {
[self setAuthToken:nil];
}
- (NSString *)authToken {
return [self secureValueForKey:AUTH_TOKEN_KEY];
}
- (void)setAuthToken:(NSString *)authToken {
[self setSecureValue:authToken forKey:AUTH_TOKEN_KEY];
[[NSNotificationCenter defaultCenter] postNotificationName:#"token-changed" object:self];
}
- (void)setSecureValue:(NSString *)value forKey:(NSString *)key {
if (value) {
[SSKeychain setPassword:#"taliesin"
forService:SERVICE_NAME
account:key];
} else {
[SSKeychain deletePasswordForService:SERVICE_NAME account:key];
}
}
- (NSString *)secureValueForKey:(NSString *)key {
return [SSKeychain passwordForService:SERVICE_NAME account:key];
}
#end
LoginViewApi.m
#import "LoginViewController.h"
#import "AuthAPIClient.h"
#import "CredentialStore.h"
#import "SVProgressHUD.h"
#interface UIViewController ()
#property (nonatomic, strong) IBOutlet UITextField *userTextField;
#property (nonatomic, strong) IBOutlet UITextField *passwordTextField;
#property (nonatomic, strong) CredentialStore *credentialStore;
#end
#implementation LoginViewController
+ (void)presentModallyFromViewController:(UIViewController *)viewController {
LoginViewController *loginViewController = [[LoginViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:loginViewController];
[viewController presentViewController:navController
animated:YES
completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.credentialStore = [[CredentialStore alloc] init];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel:)];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Login"
style:UIBarButtonItemStyleDone
target:self
action:#selector(login:)];
[self.userTextField becomeFirstResponder];
}
- (void)login:(id)sender {
[SVProgressHUD show];
id params = #{
#"admin": self.userTextField.text,
#"taliesin": self.passwordTextField.text
};
[[AuthAPIClient sharedClient] postPath:#"/auth/login.json"
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *authToken = [responseObject objectForKey:#"auth_token"];
[self.credentialStore setAuthToken:authToken];
[SVProgressHUD dismiss];
[self dismissViewControllerAnimated:YES completion:nil];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.response.statusCode == 500) {
[SVProgressHUD showErrorWithStatus:#"Something went wrong!"];
} else {
NSData *jsonData = [operation.responseString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData
options:0
error:nil];
NSString *errorMessage = [json objectForKey:#"error"];
[SVProgressHUD showErrorWithStatus:errorMessage];
}
}];
}
- (void)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Any help or for more questions please let me know cheers :)
Endpoint Addressing
I don't know how AFNetworking handles remote addresses but I think you are making a simple mistake when calling localhost from iOS to contact your web-service. The thing is that iOS is an operating system and it has its own localhost. Thus, when you think you are calling a remote web-service you are actually asking iOS to look within itself for this service. Therefore, wether you are running your rails web-service locally or on an actual remote server, find out the IP address for the server where the service is running and use that as an endpoint rather than localhost.
So update everything that points to your service to use an IP. Don't change it for 127.0.0.1, that would have the same effect.
For example:
#define BASE_URL #"http://admin:taliesin#192.168.0.1:3000"
Authentication: iOS
Assuming your web-service supports, that is, you have configured basic http authentication; then authenticating from iOS should not be a huge problem.
If you were to use RESTKit, it would be as simple as:
RKObjectManager *objectManager = [RKObjectManager sharedManager];
objectManager.client.authenticationType = RKRequestAuthenticationTypeHTTPBasic;
objectManager.client.username = username;
objectManager.client.password = password;
I use Apple's KeychainItemWrapper for storing/retrieving credentials on iOS.
//Store Account on Keychain (disk) for persistence.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
KeychainItemWrapper *accountItem = appDelegate.accountItem;
[accountItem setObject:password forKey:(__bridge id)kSecValueData];
[accountItem setObject:username forKey:(__bridge id)kSecAttrAccount];
username = password = nil; //keep account information only in the keychain.
I don't know if your code is correct but it should not be that complicated to handle basic http auth. Perhaps AFNetworking does not abstracts it as much as RESTKit does? Or perhaps you are not using the right methods from AFNetworking to do basic http auth? Basic auth does not require an access token and thus I suggest you read a little more about basic auth before implementing it.
Authentication: Rails
As for implementing authentication on Rails, it should not be too complicated either. All you need to do is to configure your controller to present an authentication challenge to the incoming request with basic http auth. One way to do this is by using before_filter: authenticate. Here is an example.
I think Railscasts is superb and they happen to have a tutorial on basic http auth and one specifically for rails 3.1. authentication.
Cheers.