MobileSDKを使わずにSalesforceにアクセスするiPhoneアプリを作る【認証編】

More than 5 years have passed since last update.

Mobile SDKを使うとSalesforceにアクセスするモバイルアプリケーションが簡単に作れそうですが、単一の組織にログインするのが前提なため要件に合わず、今回はMobile SDKを使わずに作ってみましたので基本事項をまとめておきます(XcodeでのiPhoneアプリ開発の知識があるの前提です)。

Salesforceの認証(OAuth2.0)については、こちらをまず読んでおくと分かりやすいです。

https://wiki.developerforce.com/page/JP:Digging_Deeper_into_OAuth_2.0_at_Salesforce.com


接続アプリケーションの登録

開発用のSalesforce組織にログインし、「設定>アプリケーション」から接続アプリケーションを登録します。

ここで発行される「コンシューマ鍵」(=client_id)が認証の実装に必要です。

接続アプリケーション


StoryboardでUIの大枠を作る

まずは簡単に、認証してユーザ情報を表示するだけのアプリを作ります。

新規プロジェクトで、Master-Detail Applicationをひな形に、


  • Master ViewにはSign In用のボタン代わりのセルと、取得したユーザ情報を表示する用のセルをstatic cellとして置きました。

  • Detail Viewには認証のページを表示する為のUIWebViewを置きました。

Storyboard


OAuthでの認証

UIWebViewの初期表示として、認証画面に飛ばします。

クライアントアプリケーション用の認証方式、User-Agent Flowを使うため、response_type=tokenを指定します。


SEDetailViewController.m

- (void)viewDidLoad

{
[super viewDidLoad];

// OAuthの認証画面を初期表示(User-Agent Flow)
NSString *authorizeURL = @"https://login.salesforce.com/services/oauth2/authorize?response_type=token&client_id=3MVG9I1kFE5Iul2Cbahhzus9WVFyGSQGrQ3gTYeMzkJGbA_43hAg0fb57FTxZkWASpInGI4lSg3gpzlL4WErb&redirect_uri=test%3A%2F%2Fcallback&display=touch";
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:authorizeURL]];

_webview.delegate = self;
[_webview loadRequest:req];
}


認証が終わった時のtest://callbackの処理をhookし、パラメータで返ってくる認証情報をバラします。

取得したaccess_tokenを使用して、idサービスでユーザの情報を取得します。


SEDetailViewController.m

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

{
NSString *absoluteURL = request.URL.absoluteString;

// callback先以外の場合は通常のページ遷移
if ([absoluteURL rangeOfString:@"test://callback"].location == NSNotFound) return YES;

// #以降のパラメータをバラす
NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:@"(\\w+)=([^&]+)" options:0 error:nil];
NSArray *matches = [re matchesInString:absoluteURL options:0 range:NSMakeRange(0, absoluteURL.length)];
NSMutableDictionary *authInfo = @{}.mutableCopy;

for (NSTextCheckingResult *r in matches) {
NSString *k = [absoluteURL substringWithRange:[r rangeAtIndex:1]];
NSString *v = [absoluteURL substringWithRange:[r rangeAtIndex:2]];
authInfo[k] = [v stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
}

// User-Agent Flowなのでaccess_tokenが直接返ってくる
NSString *accessToken = authInfo[@"access_token"];

// 取得したaccess_tokenを使ってidサービスに接続。ユーザ情報を取得する

// access_tokenをAuthorizationヘッダへ
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPAdditionalHeaders = @{@"Authorization": [NSString stringWithFormat:@"Bearer %@", accessToken]};
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

// idサービスのURLは'id'パラメータで返ってくる
NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:authInfo[@"id"]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// 取得したユーザ情報をMain Viewに渡して画面戻る
NSDictionary *idInfo = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// メインスレッドで実行
[self performSegueWithIdentifier:@"oauthSuccess" sender:@{@"authInfo":authInfo, @"idInfo":idInfo}];
}];
}];
[task resume];

return NO;
}


ソースコード全体はこちら

動かしてみるとこんな感じです(YouTube)

エラー処理等は特に入れてない基本部分のみですが、これでaccess_tokenを取得し、APIの呼び出しができました。