3

皆さん、アプリのログイン資格情報の認証に問題があります。現在、ローカルホストから実行されている Rails Web サービスがあります。これは、機能を表示するためのパスワード資格情報を持つ管理者ユーザーのメイン ログイン画面を備えています。

問題は、RESTful iOS アプリケーションを Rails アプリと一緒に実行し、これらの JSON 要求を受け取ってバイパスすることです。

私が望むのは、auth_token を使用せずに管理者とパスワードを入力する方法を作成することだけですか? キーチェーンで最初に管理者ユーザーを単純に認証することが唯一の方法のようです。フレームワークAFNetowrkingを認証に使用しています.SSKeychainはアカウントのラッパーで、SVProgressHUDは軽量hudです

.JSON および XML リクエストも i ターミナルに記録されていますが、このエラーでサーバーに接続できないために失敗しています。

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."}

これは、authClientの資格情報を保存する方法です。必要なのは、Webサービスクライアントへのログインに使用されるのと同じ情報を指定することだけです。

ユーザー名:admin およびパスワード:taliesin

しかし、これを行う方法がわからない?

これらは、AuthAPIClient、CredentialsStore、およびLoginViewControllerについて私が持っているものです

誰かがこれを行うためのより簡単な方法を知っている場合は、更新してください。教えていただければ幸いです。

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

ヘルプやその他の質問については、乾杯をお知らせください:)

4

1 に答える 1

1

エンドポイントのアドレス指定

がリモート アドレスをどのように処理するかはわかりませんが、から電話して Web サービスに連絡するAFNetworkingときに単純な間違いを犯していると思います。問題は、それがオペレーティング システムであり、独自の. したがって、リモート Web サービスを呼び出していると考えるとき、実際には、このサービスを検索するように求めていることになります。したがって、Rails Web サービスをローカルで実行している場合でも、実際のリモート サーバーで実行している場合でも、サービスが実行されているサーバーの IP アドレスを見つけて、それをエンドポイントではなくエンドポイントとして使用します。localhostiOSiOSlocalhostiOSlocalhost

そのため、サービスを指すすべてのものを更新して、IP を使用します。127.0.0.1同じ効果がある ため、変更しないでください。

例えば:

#define BASE_URL @"http://admin:taliesin@192.168.0.1:3000"

認証: iOS

Web サービスがサポートしている、つまり、基本的な http 認証を構成していると仮定します。からの認証iOSは大きな問題にはなりません。

を使用する場合は、次RESTKitのように簡単になります。

RKObjectManager *objectManager = [RKObjectManager sharedManager];
objectManager.client.authenticationType = RKRequestAuthenticationTypeHTTPBasic;
objectManager.client.username = username;
objectManager.client.password = password;

KeychainItemWrapperiOSで資格情報を保存/取得するためにAppleを使用しています。

//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.

あなたのコードが正しいかどうかはわかりませんが、それほど複雑ではないはずbasic http authです。おそらくAFNetworking、それほど抽象化されていRESTKitませんか?または、適切な方法を使用していないAFNetworking可能性がありbasic http authます。基本認証はアクセストークンを必要としないため、実装する前に基本認証についてもう少し読むことをお勧めします。


認証: Rails

での認証の実装に関してはRails、あまりにも複雑であってはなりません。あなたがする必要があるのは、あなたのコントローラを構成して、入ってくるリクエストに認証チャレンジをbasic http auth. これを行う 1 つの方法は、 を使用することbefore_filter: authenticateです。ここにがあります。

Railscasts はすばらしいと思います。基本的な http 認証に関するチュートリアルと、 Rails 3.1専用のチュートリアルがあります。認証

乾杯。

于 2012-12-07T15:56:09.270 に答える