Yahoo! ID連携

iOSアプリ

  • Hybridフロー
  • Implicitフロー

iOS(Hybridフロー)

iOSのHybridフローのサンプルコードの説明をします。



ライブラリーをプロジェクトに追加する

Yahoo! ID連携 iOS SDKを任意の場所にダウンロードして解凍してください。
解凍後、YConnectSDK.xcodeprojをアプリケーションのプロジェクトに追加してください。詳細な手順を下記に示します。

  1. XCodeでアプリケーションのプロジェクトを開いてください。

  2. XCodeのメニューから"File" > "Add Files To <プロジェクト名>"を選択してください。

  3. 解凍したYahoo! ID連携 iOS SDK内のYConnectSDK.xcodeprojを選択し、"Add"してください。



プロジェクトの設定

はじめにYahoo! ID連携 iOS SDKを利用するためにプロジェクトの設定を行います。

まずはビルドターゲットの"Build Phase"を開き、"Link Binary With Libraries"の"+"ボタンを押してください。

ダイアログが表示されるので、WorkspaceからlibYConnect.aを選択し、"Add"してください。

次にYahoo! ID連携 iOS SDK内のヘッダファイルをimportするために設定を行います。

ビルドターゲットの"Build Settings"を開き、設定項目中の"Header Search Paths"にYahoo! ID連携 iOS SDKのパスを追加します。

最後にコールバックURLを設定します。

ビルドターゲットの"Info"を開き、"URL Types"を展開してください。

"+"ボタンを押すと入力フォームが表示されるので、"identifier"に一意な値を、

"URL schemes"にはこのschemeはClient ID登録時に発行されるカスタムURIスキーム「yj-xxxxx」を指定してください。

"Identifier"に指定する値は"Bundle identifier"と同じ値が推奨されています。

また、カスタムURIスキームはアプリケーションの管理から変更可能です。


設定の初期化をする

  1. Info.plistにClient ID, コールバックURL, レスポンスタイプ, スコープ(複数ある場合はスペース区切り)を記載してください

  2. plistに記載するキーと値の内訳は下記のとおりです。

  3. Key Type 説明 入力例
    YConnectClientIdStringClient IDを指定します。dj00zaiZpPXNYeG5tRXJVVlLzPuWNM
    vbnN1bWVyc2VjcmV0Jng9ZWU-
    YConnectRedirectUriStringClient ID発行時に登録したコールバックURIを指定します。yj-xxxxx:/
    YConnectDisplayStringログイン画面、同意画面のテンプレートの種類を指定する場合に利用します。touch
    (任意のパラメーターです)
    YConnectResponseTypeString「code id_token」「code token」「code id_token token」のいずれかを指定してください。code%20id_token
    ※URLエンコードが必要です。
    YConnectScopeStringUserInfo APIから取得できる属性情報を指定できます。openid address
    YConnectBailBooleanYESにすると同意画面で「同意しない」ボタンをクリックした際にcodeパラメーターを付加せずにredirect_uriへリダイレクトさせます。指定しない場合はYahoo!トップへ遷移します。YES
    (任意のパラメーターです)
    YConnectMaxAgeNumber最大認証経過時間を指定します。指定された秒数よりも認証日時が経過していた場合は再認証が必要です。3600
    (任意のパラメーターです)


Authorizationエンドポイントにリクエストして同意画面を表示する

YConnectManagerクラスにはHybridフローで必要なメソッドがすべて実装されています。
YConnectManagerクラスを使ってSafariに同意画面を表示させます。

なお、サンプルコードはStoryboardを使用しています。

YConnectManagerクラス

メソッド説明
+ (instancetype)sharedInstanceシングルトンパターンのインスタンスを取得する。
- (NSURL *)generateAuthorizationUriWithState:(NSString *)state
  prompt:(NSString *)prompt
  nonce:(NSString *)nonce
同意画面のURLを取得する。
- (void)requestAuthorizationWithState:(NSString *)state
  prompt:(NSString *)prompt
  nonce:(NSString *)nonce
Safariで同意画面を表示する。

OIDCPromptクラス

定数フィールド値説明
YConnectConfigPromptConsentユーザーの再認可のための定数です。
YConnectConfigPromptLoginユーザーの再認証のための定数です。
YConnectConfigPromptNone同意画面非表示のための定数です。(ログイン状態でなかった場合、過去に同意済みでなかった場合はエラーが返却されます)
YConnectConfigPromptSelectAccountID切り替え画面を強制表示するための定数です。
ViewController.h
@interface ViewController : UIViewController

- (IBAction)login:(id)sender;

ViewController.m
// ログイン用のアクションを作成
- (IBAction)login:(id)sender
{
    [self getStateAndNonce:^(NSString *state, NSString *nonce) {
        if ([state length] == 0 || [nonce length] == 0) {
            // エラーハンドリング
        } else {
            YConnectManager *yconnect = [YConnectManager sharedInstance];
      // Safariで同意画面を表示する
            [yconnect requestAuthorizationWithState:state prompt:nil nonce:nonce];
        }
    }];
 
}
 
- (void)getStateAndNonce:(void (^)(NSString *state, NSString *nonce))handler
{
    // state, nonceの取得(認証サーバー側にstateとnonceを発行するための任意のURLを用意してください)
    NSURL *url = [NSURL URLWithString:@"https://example.com/issue.php"];
    NSError *error = nil;
    NSData *jsonData = [NSData dataWithContentsOfURL:url options:kNilOptions error:&error];
    NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
    NSString *state = [jsonResponse objectForKey:@"state"];
    NSString *nonce = [jsonResponse objectForKey:@"nonce"];
 
    if ([state length] == 0 || [nonce length] == 0) {
        // 値の取得の失敗時のエラー処理
        handler(nil, nil);
    } else {
        handler(state, nonce);
    }
}

認証サーバー側で発行するstateとnonceは独自の仕様でランダムな文字列を生成してデータベースなどに保存してください。
stateはAuthorizationエンドポイントからのコールバックURL受取時と認証サーバーへの認可コード連携時に、nonceはIDトークンを復号時の検証に必要です。

各パラメーター値の詳細についてはAuthorizationエンドポイントを参照してください。

サンプルでは各パラメーターを乗せたURLをSafariで読み込んでいます。


コールバックURLを受け取り、認可コード、Access Token、ID Tokenを抽出する

同意後に返されるコールバックURLをAppDelegateで受け取り、Access Tokenなどを抽出します。

YConnectManagerクラス

メソッド説明
- (void)parseAuthorizationResponse:(NSURL *)uri
  handler:(YConnectAuthorizationEndpointResponseHandler)handler
コールバックURLのフラグメントに付加
されたパラメーターを抽出する。
- (void)fetchAccessToken:(NSString *)code
  handler:(YConnectTokenEndpointResponseHandler)handler
認可コードを用いてAccess Tokenを
取得する。
- (NSString *)accessTokenStringAccess Tokenを取得する。
- (NSInteger)accessTokenExpirationAccess Tokenの有効期限を取得する。
- (NSString *)hybridIdTokenStringID Tokenを取得する。
AppDelegate.m
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
    //コールバックURLに指定したURLだった場合、結果を表示するResultViewControllerに遷移する
    if ([url.scheme isEqualToString:@"yj-xxxxx"]) {
        YConnectManager *yconnect = [YConnectManager sharedInstance];
        [yconnect parseAuthorizationResponse:url handler:^(NSError *error) {
            // エラーハンドリング
            if (error) {
                ...
            }
 
            // Access Token、ID Tokenを取得
            [yconnect fetchAccessToken:yconnect.authorizationCode handler:^(YConnectBearerToken *retAccessToken, NSError *error) {
                // エラーハンドリング
                if (error) {
                    ...
                }
 
                // Access Token、ID Tokenを取得
                NSString *accessToken = [yconnect accessTokenString];
                NSString *idToken = [yconnect hybridIdTokenString];
                ...
            }];
        }];
 
        ViewController *viewController = [self.window.rootViewController.childViewControllers objectAtIndex:0];
        [viewController performSegueWithIdentifier:@"ToResultPage" sender:viewController];
        return YES;
    }
    return NO;
}


取得した認可コードを認証サーバに連携する

認証サーバー側に認可コードとstateを渡し、認証サーバはTokenエンドポイントにリクエストしてAccess Token/Refresh Token/ID Tokenを発行します。

ResultViewController.m
// コールバックURLから各パラメーターを抽出
YConnectManager *yconnect = [YConnectManager sharedInstance];

//認証サーバー側にcodeとstateを渡すURLを作成してください
NSURL *url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"http://example.com/auth.php?code=%@&state=%@",yconnect.authorizationCode,yconnect.state]];
/*
 * webviewを起動して認証サーバに送信してください
 */


取得したID Tokenを検証した上でユーザー識別子を取得する

オプションでレスポンスタイプにID Tokenを指定した場合、ID Tokenの暗号化された文字列が返されます。
この文字列をクライアント側で検証し、ユーザー識別子やID Tokenの発行元などの情報を取得します。

ResultViewController.m
{
    ...
    // コールバックURLから各パラメーターを抽出
    YConnectManager *yconnect = [YConnectManager sharedInstance];
 
   /** IDトークンの検証が必要です
     *
     * 検証手順については下記リンク先の「ID Tokenの検証手順」をご参照ください
     * https://developer.yahoo.co.jp/yconnect/v2/id_token.html
     *
     * 検証に必要な公開鍵証明書は以下から取得が可能です
    **/
    NSString *publicKey = [self getDataFrom:YConnectConfigV2PublicCertEndpoint];
    NSData *data = [publicKey dataUsingEncoding:NSUTF8StringEncoding];
    id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
 
    ...
 
    // 検証済みのIDトークンを利用する
    IdTokenObject *idTokenObject = [yconnect idTokenObject];
}
 
- (NSString *)getDataFrom:(NSString *)url
{
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
     [request setHTTPMethod:@"GET"];
     [request setURL:[NSURL URLWithString:url]];
  
     NSError *error = nil;
     NSHTTPURLResponse *responseCode = nil;
  
     NSData *oResponseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseCode error:&error];
 
     if ([responseCode statusCode] != 200) {
         ...
         return nil;
     }
  
     return [[NSString alloc] initWithData:oResponseData encoding:NSUTF8StringEncoding];
}

各パラメーターはID Tokenオブジェクトのプロパティーに保持されているので、必要に応じて取り出して利用してください。


UserInfo APIにリクエストしてユーザー識別子を取得する

Access Tokenを用いてユーザー識別子などを取得します。

YConnectManagerクラス

メソッド説明
- (void)fetchUserInfo:(NSString *)accessTokenString
  handler:(YConnectUserInfoEndpointResponseHandler)handler
UserInfo APIにリクエストする。
ResultViewController.m
// UserInfo情報を取得
- (IBAction)fetchUserinfo:(id)sender
{
    YConnectManager *yconnect = [YConnectManager sharedInstance];
    NSString *accessToken = [yconnect accessTokenString];
  
    // Access Tokenが空
    if ([accessToken length] == 0) {
        ...
        return;
    }
 
    [yconnect fetchUserInfo:accessToken handler:^(YConnectUserInfoObject *userInfoObject, NSError *error) {
        // エラーハンドリング
        if (error) {
            ...
        }
 
        // UserInfo情報からユーザー識別子を取得
        NSString *userid = yconnect.userInfoObject.sub;
        ...
     }];
}


Access Tokenを更新する

Refresh Tokenをつかって有効期限切れのAccess Tokenを更新します。

YConnectManagerクラス

メソッド説明
- (void)refreshAccessToken:(NSString *)refreshToken
  handler:(YConnectTokenEndpointResponseHandler)handler
Access Tokenを更新する
[yconnectManager refreshAccessToken:yconnectManager.refreshTokenString handler:^(YConnectBearerToken *accessToken, NSError *error) {
    if (/* エラーレスポンスが"Invalid_Token"であるかチェック */) {
        // 再度認証を行う必要があります
    }
 
    //  更新に成功したAccess Tokenを利用できます
    ...
}];


Access Tokenなどの保存について

Access Token、ID Token、UserInfo情報の保存は、悪意のある外部アプリケーションから盗みとられないように注意が必要です。 取得したトークンやユーザー情報を保存する場合には、適宜暗号化や難読化し外部から読み取られないようにしてください。



Yahoo!知恵袋で調べる