Takahiro Octopress Blog

-1から始める情弱プログラミング

iOSでGoogle OAuth認証がしたい

iOSネイティブアプリにGoogle OAuth認証機能を実装する方法

Google OAuth認証はWebアプリであれば多くの情報が載っているのですが、なぜかiOSネイティブアプリになると情報が全然見つからない…。
ということでその方法をまとめてみることにした。

まず、ネット上で検索してみるとiOSでOAuth認証をするためのライブラリは幾つか作られているようでした。
その中でも、Googleが提供しているgtm-oauth2がよく使われているらしい。
ま、Googleが提供しているのであれば、安心して使えるだろうということで、ここではgtm-oauth2を使った方法で説明します。

設定編

開発に入る前にGoogle Consoleで設定する必要があります。
1: OAuthのClientIDを作成する
左メニューからAPIS & AUTH > Credentialsを選択します。
OAuthと書かれた下にCreate new Client IDというボタンがあります。これをクリックするとポップアップが出てきます。このポップアップの中で必要な選択と入力は下記画像のようになります。
Create new Client ID
すると、下記画像のようにCLIENT IDCLIENT SECRETが表示されます。
Client ID & Client Secret

2: Consent Screenを設定する
次にConsent Screenを設定します。これを設定しないとErrorが発生してしまいます。
左メニューからAPIS & AUTH > Consent Screenを選択します。
下記画像のようにEMAIL ADDRESSPRODUCT NAMEの2箇所を入力してSaveボタンをクリックしましょう。
Consent Screenの設定

3: 利用するAPIを設定する
最後に利用したいAPIの設定をONにしておきましょう。
左メニューからAPIS & AUTH > APIsを選択します。
下記画像のように利用したいAPIのSTATUSをONにしましょう。
APIをONにする

これで設定は完了です。
続いて開発の説明に入ります。

開発編

1: GoogleからソースをGET
早速、Googleが配布しているソースをもらいに行きます。
Googleのgtm-oauth2サイトでも書かれているようにsvnを使って、ソースを落とします。
ソースを保存する場所を決めたら、その配下で下記コマンドを実行。

1
svn checkout http://gtm-oauth2.googlecode.com/svn/trunk/ gtm-oauth2-read-only

もしかしたら、途中でRejectかtemporaryかpermanentか聞かれるかもしれません。筆者はtemporaryにしました。
ソースを落とした後は公式ドキュメントに書かれている通り、進めていきます。

2: ダウンロードしたソースを自身のXcodeプロジェクトに追加
OAuth認証機能を実装したいXcodeプロジェクトを作成します。ここにOAuthに必要なソースを追加します。
必要なソースは
・GTMOAuth2Authentication.h/m
・GTMOAuth2SignIn.h/m
・GTMHTTPFetcher.h/m
・GTMOAuth2ViewControllerTouch.h/m
・GTMOAuth2ViewTouch.xib
です。
格納場所は下記画像を見てください。
必要なソースの格納場所

ほとんどの人がXcode5.1.1でプロジェクトを作ると思うのですが、デフォルトARC対応プロジェクトとなっていると思います。
そのため、コンパイルオプションOther Linker Flagsを設定する必要があります。
コンパイルオプションの設定
Other Linker Flagsの設定

3: Googleからダウンロードしたソースを使うために必要なFrameworkをプロジェクトに追加する
Security.frameworkとSystemConfiguration.frameworkを追加します。
必要なframeworkを追加

4: ソースを書く
OAuth認証機能を実装するUIViewControllerをプロジェクトに追加しましょう。ここでは名前をViewControllerとします。
ViewController.mファイルのソース

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#import "ViewController.h"
#import "GTMOAuth2Authentication.h"
#import "GTMOAuth2ViewControllerTouch.h"

@interface ViewController ()

@property (nonatomic, retain) GTMOAuth2Authentication *auth;

-(void) startLogin;

@end
static NSString *const kKeychainItemName = @"GOAuthTest";
static NSString *const scope = @"https://www.googleapis.com/auth/calendar";// Calendar APIを利用する場合のscope
static NSString *const clientId = @"xxxxxxxx.apps.googleusercontent.com";// 発行されたClient IDを設定
static NSString *const clientSecret = @"xxxxxxxx";// 発行されたClient Secretを設定
static NSString *const hasLoggedIn = @"hasLoggedInKey";// NSUserDefaultに保存するための文字列

<省略>

- (void)viewDidAppear:(BOOL)animated
{
  // アプリ起動してOAuth認証動作を開始する
  [self startLogin];
}

// OAuth認証の開始
- (void)startLogin
{
  // 既に認証をしたかどうか確認
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  BOOL hasLoggedin = [defaults boolForKey:hasLoggedIn];

  if(hasLoggedin == YES) {
      // 認証したことがある場合
      self.auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
                                                                        clientID:clientId
                                                                    clientSecret:clientSecret];
      // アクセストークンの取得
      [self authorizeRequest];
  } else {
      // 認証したことがない場合
      GTMOAuth2ViewControllerTouch *gvc = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope
                                                                                     clientID:clientId
                                                                                 clientSecret:clientSecret
                                                                             keychainItemName:kKeychainItemName
                                                                                     delegate:self
                                                                             finishedSelector:@selector(viewController:finishedWithAuth:error:)
      ];
      // 認証画面の表示
      [self presentViewController:gvc animated:YES completion:nil];
  }
}

// 認証後に実行する処理
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
    finishedWithAuth:(GTMOAuth2Authentication *)auth
               error:(NSError *)error
{
  if(error != nil) {
      // 認証失敗
  } else {
      // 認証成功
      self.auth = auth;
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      [defaults setBool:YES forKey:hasLoggedIn];
      [defaults synchronize];

      // アクセストークンの取得
      [self authorizeRequest];
  }

  // 認証画面を閉じる
  [viewController dismissViewControllerAnimated:YES completion:nil];
}

// アクセストークンの取得処理
- (void)authorizeRequest
{
  NSLog(@"%@", self.auth);
  NSMutableURLRequest *req = [NSMutableURLRequest alloc] initWithURL:self.auth.tokenURL];
  [self.auth authorizeRequest:req completionHandler:^(NSError *error) {
      NSLog(@"%@", self.auth);
  }];
}
  1. 実機で動作を確認
    ソースが書けたら、実際にアプリを起動して見てみましょう。
    認証画面が表示されます。
    認証画面

メールアドレスとパスワードを入力すると、認証の許可画面が表示されます。
許可画面
許可をすると、開発者の作成する画面に戻ります。

さて、いかがだったでしょうか?
今回はGoogle APIの利用まで書いていませんが、OAuthができてしまえば、そんなに難しくはないでしょう。たぶん笑

参考:
gtm-oauth2でOAuth認証してgoogleのAPIを使う
invalid_client no application name – Stack Overflow

Comments