忍者ブログ
プログラミングとか日常とかの覚書っぽいなにか
[38] [37] [36] [35] [34] [33] [32] [31] [30] [29] [28]
×

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

前回に引き続きiOS用Twitterクライアント作成の解説です。
今回はTwitterへのサインイン(ここではOAuth認証・認可の手続き)を進めたいと思います。

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


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 というクラスを使用していますが、私たちがこのクラスを直接触ることはないので、特に気にする必要はありません。


OAuth認証の実行

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

前回の最後に準備したプロジェクトを使い、UITableViewController の派生である MasterViewController クラスに実装コードを入れていくことにします。

MasterViewController クラスに GTMOAuthAuthentication のインスタンス変数を持たせておきます。MasterViewController.m の中の @implementation の部分を以下のように記述します。
#import "GTMOAuthAuthentication.h"
#import "GTMOAuthViewControllerTouch.h"

@implementation MasterViewController {
    // OAuth認証オブジェクト
    GTMOAuthAuthentication *auth_;
}

これで、MasterViewController クラスにインスタンス変数 auth_ を持たせることができます。
一昔前はヘッダファイルの @interface の方にインスタンス変数を併せて記載していましたが、現在は外部から直接参照されないインスタンス変数(他の言語でいうところのprivateメンバ変数)は @implementation の方に書くことが推奨されているようです。

次にコードを追加していきます。
ビュー作成完了時(viewDidLoadメソッド)で、 GTMOAuthAuthentication を生成し、インスタンス変数 auth_ に保持します。

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 asyncSignIn];
}

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

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

アプリ登録時にも説明したように、通常はクライアント型アプリケーションはCallback URLを使わないのですが、GTMOAuthではこれを指定しておかないと正常に実行されないため、ダミーのURLを callback プロパティで指定しておく必要があります。
// 認証処理
- (void)asyncSignIn
{
    NSString *requestTokenURL = @"https://api.twitter.com/oauth/request_token";
    NSString *accessTokenURL = @"https://api.twitter.com/oauth/access_token";
    NSString *authorizeURL = @"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:[NSURL URLWithString:requestTokenURL]
                      authorizeTokenURL:[NSURL URLWithString:authorizeURL]
                      accessTokenURL:[NSURL URLWithString:accessTokenURL]
                      authentication:auth_
                      appServiceName:keychainAppServiceName
                      delegate:self
                      finishedSelector:@selector(authViewContoller:finishWithAuth:error:)];

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

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

ただし、上記のコードは起動時に必ず認証画面を表示するようになっています。2回目以降の起動時にKeyChainの情報を使うようにする方法は後述します。

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

ユーザがキャンセルしたり接続エラーが発生したりなどにより認証処理が失敗すると、引数 error が nil 以外になっています。今回はAlertを表示して失敗を知らせています。なので、MasterViewController が UIAlertViewDelegate プロトコルを採用するよう @inteface 定義を書き換えておく必要があります。
// 認証エラー表示AlertViewタグ
static const int kMyAlertViewTagAuthenticationError = 1;

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

// UIAlertViewが閉じられた時
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    // 認証失敗通知AlertViewが閉じられた場合
    if (alertView.tag == kMyAlertViewTagAuthenticationError) {
        // 再度認証
        [self asyncSignIn];
    }
}

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

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 authorized = [GTMOAuthViewControllerTouch
                       authorizeFromKeychainForName:kKeychainAppServiceName
                       authentication:auth_];
    if (authorized) {
        // 認証済みの場合はタイムライン更新
        [self asyncShowHomeTimeline];
    } else {
        // 未認証の場合は認証処理を実施
        [self asyncSignIn];
    }
}

KeyChainに登録する際のサービス名をメソッドの外で kKeychainAppServiceName という名前で定義しました。上で定義した asyncSignIn メソッドの中のKeyChain登録サービス名もこれを共通して使うようにしましょう。


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

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

[参考] GTMOAuthでTwitterなどのOAuthを行う方法
http://www.awaresoft.jp/ios-dev/item/90-gtmoauth

拍手

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]
カレンダー
03 2024/04 05
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
ブログ内検索
あ~いい漢字