忍者ブログ
プログラミングとか日常とかの覚書っぽいなにか
[26] [25] [24] [23] [22] [21] [20] [19] [18] [17] [16]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

iPhone用Twitterクライアント作成中、今回はとりあえずTwitterへのサインイン(ここではOAuth認証・認可の手続き)まで進めたいと思います。

GTMOAuthライブラリにはいくつかクラスが含まれていますが、アプリから直接扱うのは以下の2つ。
  • GTMOAuthAuthentication
  • GTMOAuthViewControllerTouch

(2011/06/28)
2回目以降起動時のKeyChainからの認可情報取得について追記


(2012/06/19)
iOS5/ARC対応版の記事を書きましたので、そちらを参照してください。この記事の内容は古いです。

GTMOAuthAuthenticationクラスの役割

GTMOAuthAuthenticationクラスは、アクセストークンと呼ばれるアカウント識別情報を保持し、OAuthプロトコルに基づいて、サービスプロバイダ(今回の場合はTwitter)への要求に署名情報を付けるという役割を持っています。

具体的にどのようなことかというのを実際の例で示してみましょう。

Twitter APIには、OAuth認証による署名(サイン)を必要とするものと、署名を必要としないものの2種類があります。ブラウザでサインインしていなくても見えるような情報(例えば公開ユーザのツイート)は、署名なしでも実行することができます。

例えば、私(fresh_homepie)の最新のツイート10件分の取得を署名なしで行い、JSON形式で受け取る場合、以下のような要求をすることになります。(後のものと比較しやすくするため改行を入れていますが、実際には改行や空白文字は含まれません。)

(1) 署名なしのHTTP要求

http://api.twitter.com/1/statuses/user_timeline.json
    ?count=10
    &screen_name=fresh_homepie

一方、まったく同じ要求を行う際に、OAuth認証をによる署名を含めた場合には以下のようになります。(XXXXの部分は実際は別の文字列です。)

(2) 署名ありのHTTP要求

http://api.twitter.com/1/statuses/user_timeline.json
    ?count=10
    &screen_name=fresh_homepie
    &oauth_consumer_key=XXXXXXXXXXXXXXXXXXXX
    &oauth_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    &oauth_signature_method=HMAC-SHA1
    &oauth_version=1.0
    &oauth_nonce=XXXXXXXXXXXXXXXXXXXX
    &oauth_timestamp=XXXXXXXXXX
    &oauth_signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

GTMOAuthAuthenticationの役割は、「アカウント識別情報をもとに、(1)の署名なし要求を(2)の署名あり要求に変換する」ということにあります。

上の2つの要求を比較すると、「oauth_xxxx=○○○○」という引数がいくつか追加されていますが、これらがOAuthの署名情報になります。これらの署名情報は、アプリ登録時に割り当てられたコンシューマキーや、OAuth認証時に受け取ったアクセストークンと呼ばれる情報などを使用して生成されていますが、その生成過程についてはここでは割愛します。GTMOAuthAuthenticationが自動的にやってくれるので、特に知らなくても大丈夫です。


GTMOAuthViewControllerTouchクラスの役割

GTMOAuthViewControllerTouchは、iOS端末でOAuth認証を使用してサインインするためのビューを提供するビューコントローラです。具体的には、OAuth認証を行うTwitterクライアントではおなじみの以下の画面を出して、認証・認可の手続きを行ってくれます。


正常に認可されると、アクセストークンなどの情報をGTMOAuthAuthenticationに渡し、上記の署名を行えるように準備します。

なお、このクラスは内部でGTMOAuthSignInというクラスを使用していますが、私たちがGTMOAuthSignInを直接触ることはないので、特に気にする必要はありません。


OAuth認証の実行

実際にOAuth認証でサインインを行う手続きとしては以下の通りになります。
ここではひとまず、毎回起動時に行うようにしています。
  1. アプリ登録時に取得したコンシューマキー、コンシューマシークレットを指定して、GTMOAuthAuthenticationオブジェクトを生成。
  2. 生成されたGTMOAuthAuthenticationと各種リクエスト用URLを指定してGTMOAuthViewControllerTouchオブジェクトを生成し、OAuth認証ビューを表示。
  3. 認証ビューが閉じられたら、OAuth認証処理は完了。

今回はUITableViewControllerの派生(既定ではRootViewController)上で実装していくことになります。
まずは、ビュー作成完了時(viewDidLoadメソッド)で、GTMOAuthAuthenticationを生成します。

GTMOAuthAuthenticationクラスの initWithSignatureMethod:consumerKey:privateKey: メソッドで初期化を行いますが、最初の引数は署名方式を指定します。Twitterの場合は現時点で「HMAC-SHA1」という方式のみをサポートしているので、「kGTMOAuthSignatureMethodHMAC_SHA1」を指定しなければいけません。
第2引数と第3引数にはそれぞれconsumerKey(コンシューマキー)とconsumerSecret(コンシューマシークレット)を指定しますが、ここにはクライアントアプリの登録時に取得されたものを指定してください。
- (void)viewDidLoad
{
    [super viewDidLoad];

    // GTMOAuthAuthenticationインスタンス生成
    // ※自分の登録アプリの Consumer Key と Consumer Secret に書き換えてください
    NSString *consumerKey = @"XXXXXXXXXXXXXXXXXXXX";
    NSString *consumerSecret = @"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    auth_ = [[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
                                                        consumerKey:consumerKey
                                                         privateKey:consumerSecret];

    // 認証処理を実行
    [self signIn];
}

続いて認証処理を行います。ここは後のことを考えて singIn というメソッドで定義してあります。

OAuth認証を行ってくれるのはGTMOAuthViewControllerTouchなので、そのオブジェクトを生成して初期化し、pushViewController:animated: で表示します。
初期化時に指定するscopeとlanguageとはTwitterでは使用されないので、それぞれnilを指定しておきます。
OAuth認証処理が終了したときに呼び出すメソッドを、delegateおよびfinishedSelecter(セレクタ)で指定することができるので、現在のビューコントローラ(RootViewController)に authViewContoller:finishWithAuth:error: というメソッドを定義して、それを渡すようにしておきます。

アプリ登録時にも説明したように、Callback URLは使わないのですが、指定しておかないと正常に実行されないため、ダミーのURLをcallbackプロパティで指定しておきます。
// 認証処理開始
- (void)signIn
{
    NSURL *requestTokenURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"];
    NSURL *accessTokenURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"];
    NSURL *authorizeURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/authorize"];
    NSString* keychainAppServiceName = @"KodawariButter";

    auth_.serviceProvider = @"Twitter";
    auth_.callback = @"http://www.example.com/OAuthCallback";

    GTMOAuthViewControllerTouch *viewController;
    viewController = [[[GTMOAuthViewControllerTouch alloc] initWithScope:nil
                                                                language:nil
                                                         requestTokenURL:requestTokenURL
                                                       authorizeTokenURL:authorizeURL
                                                          accessTokenURL:accessTokenURL
                                                          authentication:auth_
                                                          appServiceName:keychainAppServiceName
                                                                delegate:self
                                                        finishedSelector:@selector(authViewContoller:finishWithAuth:error:)] autorelease];

    [[self navigationController] pushViewController:viewController animated:YES];
}

・・・一部、1行があまりにも長くなってるところがあるのは気にしない。

ところで、GTMOAuthライブラリではいったん認証が完了するとアクセストークンなどの認証情報をOSが持つKeyChainと呼ばれるパスワード管理システムに登録するようになっています。上記のコードのkeychainAppServiceNameには、KeyChainに登録する際のキーとなるサービス名を指定します。ここではアプリ名をそのままサービス名として指定しています。
2回目以降の起動時にKeyChainの情報を使うようにする方法は後述します。

次に、認証処理が完了したら authViewContoller:finishWithAuth:error: が呼ばれるようにしたので、その定義をします。

ユーザがキャンセルしたり接続エラーが発生したりなどにより認証処理が失敗すると、errorがnil以外になっています。
今回はAlertViewを表示して失敗を知らせています。なので、RootViewControllerはUIAlertViewDelegateを採用するようヘッダファイルを書き換えておく必要があります。

// 認証処理完了時
- (void)authViewContoller:(GTMOAuthViewControllerTouch *)viewContoller
           finishWithAuth:(GTMOAuthAuthentication *)auth
                    error:(NSError *)error
{
    if (error != nil) {
        // 認証失敗
        NSLog(@"Authentication error: %d.", error.code);
        UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Error"
                                                         message:@"Authentication failed."
                                                        delegate:self
                                               cancelButtonTitle:@"Confirm"
                                               otherButtonTitles:nil] autorelease];
        alert.tag = kMyAlertViewTagAuthenticationError;
        [alert show];
    } else {
        // 認証成功
        NSLog(@"Authentication succeeded.");
        // タイムライン表示
        [self showHome];
    }
}

// UIAlertViewが閉じられた時
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    // 認証失敗通知AlertViewが閉じられた場合
    if (alertView.tag == kMyAlertViewTagAuthenticationError) {
        // 特に処理なし
    }
}

// デフォルトのタイムライン表示処理
- (void)showHome
{
    // 今はまだ処理なし
}


KeyChainからの認可情報の取得

上記のソースでは起動するたびにOAuth認証を実施してしまいますが、先に説明した通り、GTMOAuthAuthenticationおよびGTMOAuthViewControllerTouchでOAuth認証を行った際に取得された認可情報(アクセストークン等)は、パスワードや認可情報を保持するためのOSのKeyChainサービスに保存されています。
従って、初回起動時にいったんOAuth認証を実行すると、有効期限の範囲内であれば、次回起動以降、再度認証を実施しなくてもよくなります。

既に認可情報が保持されている場合の認可情報の取得は、GTMOAuthViewControllerTouchクラスの authorizeFromKeychainForName:authentication: メソッドを使用して行うことができます。これを利用すると、最初に挙げた viewDidLoad メソッドは以下のように書き換えることができます。

// KeyChainサービス名
static NSString *const kKeychainAppServiceName = @"KodawariButter";

- (void)viewDidLoad
{
    [super viewDidLoad];

    // GTMOAuthAuthenticationインスタンス生成
    // ※自分の登録アプリの Consumer Key と Consumer Secret に書き換えてください
    NSString *consumerKey = @"XXXXXXXXXXXXXXXXXXXX";
    NSString *consumerSecret = @"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    auth_ = [[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
                                                        consumerKey:consumerKey
                                                         privateKey:consumerSecret];

    // 既にOAuth認証済みであればKeyChainから認証情報を読み込む
    BOOL didAuth = [GTMOAuthViewControllerTouch authorizeFromKeychainForName:kKeychainAppServiceName
                                                              authentication:auth_];

    if (!didAuth) {
        // 未認証の場合は認証処理を実施
        [self signIn];
    } else {
        // 認証済みの場合はタイムライン更新
        [self showHome];
    }
}
KeyChainに登録する際のサービス名をメソッドの外で kKeychainAppServiceName という名前で定義しています。上で定義した signIn メソッドの中のサービス名もこれを共通して使うようにしましょう。

サインインまでの処理は以上です。タイムラインの取得はまた今度ということで。

[参考] GTMOAuth Introduction (英語)
http://code.google.com/p/gtm-oauth/wiki/GTMOAuthIntroduction

[参考] GTMOAuthでTwitterなどのOAuthを行う方法
http://www.awaresoft.jp/development/35-iphone-app/90-gtm-aouth.html

拍手

PR

コメント


コメントフォーム
お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード
  Vodafone絵文字 i-mode絵文字 Ezweb絵文字


忍者ブログ [PR]
プロフィール
HN:
はむぱい
職業:
ソフト作ったりしてる人
Twitter
最新CM
[06/09 replica rolex oyster perpetual datejust]
[06/09 bracelets imitation cartier love]
[06/09 replica the oyster perpetual datejust]
[06/09 datejust rolex oyster perpetual]
[06/09 replica gold love bangle]
カレンダー
08 2017/09 10
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
ブログ内検索
あ~いい漢字