読者です 読者をやめる 読者になる 読者になる

TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

TiPlatformConnectのYammer対応作業記録

Titanium Mobile

以下のようにpull request投げて、ひとまずやるやる詐欺になりつつあったTiPlatformConnectのYammer対応を完了させました

f:id:h5y1m141:20130301071757p:plain

OAuth自体の仕組みを正確に理解してないことも影響してると思うのですが結構ハマった所がありました。将来また違ったサービス用にのTiPlatformConnect拡張するかもしれないので今後のためにコードの解説しながらドキュメントまとめておこうと思います

このエントリの目次

YammerのOAuth認証概要

YammerでのOAuth認証についてはDeveloperサイトに説明があります。

なお

Yammer OAuth2 support will soon completely replace the deprecated OAuth1.0 system at Yammer. OAuth2 is designed to be much simpler than OAuth1.0.

とあり、OAuth1.0 よりもシンプルな設計になってるOAuth2.0な実装になってるようです。

YammerのOAuth認証流れ

  1. https://www.yammer.com/dialog/oauthにアクセスすると、Yammerのログインフォームが表示されるので、ユーザIDとパスワードを入力します

※本筋と関係ないけど、このログインフォームってスマフォ用に最適化されないから、入力フィールドが小さいんですよね・・

2.入力されたユーザIDとパスワードはhttps://www.yammer.com/dialog/authenticate?client_id=xxxxxxxにPOSTされるようですが、POSTした結果、ログイン成功するとredirectされる際に、「自分で設定したredirect url」/auth?code=YOUCODEにリダイレクトされます。

3.アクセストークン取得するために、https://www.yammer.com/oauth2/access_token.jsonにGET メソッドで以下パラメータを渡してアクセスします

  • client_id : YammerのDeveloperサイト登録時に取得したclient_id (他のサービスだとconsumerKeyという呼び方をされているやつ)
  • client_secret : YammerのDeveloperサイト登録時に取得したclient_secret(他のサービスだとconsumerSecret)
  • code : リダイレクトされたURLのクエリーパラメータのcode=以降の xxxxx の部分を渡す

パラメータの指定が間違っていなければ、アクセストークンが取得出来るはずです

Yammer対応する際に参考にしたtwitter.jsのソースコード解説

解説の前に

Yammer対応にあたって、他のサービス(例:twitter.js)のソースを読んで理解した上で、必要な箇所を修正するアプローチをとりました。

twitter.jsは300行弱の分量で、人によっては大したことがないと感じるかもしれませんが、自分としては構造をつかむのに時間がかかって苦労したので、どうコードを読み進めたのか考え方をまとめておきます

  • クラスの定義をする箇所。先頭からK.prototype = xxxx.prototypeの所まで
  • クラスにて実装されてる以下のメソッド authorize() request(path, params, headers, httpVerb, callback) logout() addEventListener(eventName, callback)
  • function createAuthWindow() {..}の箇所。

先頭からK.prototype = xxxx.prototype;の所

commonJSモジュールとして利用するためのおまじないみたいなものだと思うのでここは細かい説明がなくても良いかと思います。実際この部分について手を入れた箇所はほとんどないのでここの詳細解説は省きます

クラスにて実装されてるメソッド

  • authorize()
  • request(path, params, headers, httpVerb, callback)
  • logout()
  • addEventListener(eventName, callback)

と4つありますが、logout()とaddEventListener(eventName, callback)については、名前からどんな処理をしてるのかおおよそ検討がつくので、こちらについては深く読んでいません。

authorize() 、request()の2つは、OAuthh認証のキモになりそうなのでここはしっかりと読みました。

authorize()について

authorizeという名前からして「認可」に関する処理だろうと思ってじっくり読みました。といっても、大枠としては

if (this.authorized) {
  setTimeout(function() {
  // 以下省略
} else {
  createAuthWindow.call(this);
  // 以下省略
}

という感じで、認可済かどうかを判定して、認可されてない場合にcreateAuthWindow()を実行するという感じなので、このメソッド自体はそれほど難しいことはしてないと思います

request()について

このメソッドがこのクラス内で呼ばれてる形跡がなく、最初何をする処理か検討つきませんでしたが、ふと、呼び出す側のapp.jsの方のソースを検索したら

  var twitterAuthorize = function (event) {
      twitter.addEventListener('login', function (e) {
          if (e.success) {
              Ti.App.Properties.setString('twitterAccessTokenKey', e.accessTokenKey);
              Ti.App.Properties.setString('twitterAccessTokenSecret', e.accessTokenSecret);

              twitter.request('1/account/verify_credentials.json', {}, {}, 'GET', function (e) {

という箇所を見つけました。認証&認可が済んだ状態で、twitter APIにアクセスして、何らかの情報を取得する処理でこのrequest()が利用されることに気づきました。

function createAuthWindow() {..}の箇所。

名前からして認証&認可するためのログイン用の画面を生成するんだろうなぁというのはおおよそ検討ついたのですが、全体像を中々掴めずこれが一番手強かったです。

自分がハマった原因として

webView.addEventListener('load', function(event) {
  if (event.url.indexOf(self.authorizeUrl) === -1) {
    // If we're not on the Twitter authorize page
  } else {
  
  }

で、何をやろうとしてるのかが皆目検討つかなかったから。特にevent.urlっていうのがよくわからなかったので、そのため、

webView.addEventListener('load', function(event) {
  Ti.API.info("start webview load event.event.url is: " + event.url);

として、event.url の中身をみてみる事にしました。すると

[INFO] start webview load event.event.url is: https://www.yammer.com/dialog/authenticate?client_id=xxxxxxx
[INFO] start webview load event.event.url is: https://www.yammer.com/pasonatech.co.jp/dialog/oauth?client_id=xxxx&redirect_uri=xxxxxx

という感じで、event.urlはwebViewで実際にアクセスしてるURLの情報にアクセスしており、event.url.indexOf(self.authorizeUrlの値をチェックすることで、認可済かどうかを判定していたという結論に至りました

その後ですが、

と呟いたように、各サービス別に処理方法が違うことに全く気づかず、この部分で凄ーーーく時間を費やしましたが、これが理解できたことで作業が一気に進んだ感じがします。

認可後、twitter.jsの場合には、画面上に表示される数字のpinを取得した上で、アクセストークン取得する処理に移ってるようですが

Yammer対応のyammer.jsの実装時には参考になる部分がなかったので、github.jsの処理を流用して実装しました

今後に向けて

createAuthWindow() の所の理解が中々進まなかった時に

と呟いたのですが、今でもこの部分リファクタリングしたい気持ちがあるのですが、どうやって実装していいのかあまり良いアイデアが浮かばないでいます。

もうちょっと色々勉強して、自分として理解しやすい方法が思いついたら、また手を入れてpull requestしようかなと思います。

P.S. うちの会社の得に営業系の人にもう少しYammer使って欲しく、その解決策の1つとして 彼らが日頃チェックしてると思われる@ITとかITproのニュースサイトの情報閲覧  ↓ 気になった記事をYammerに気軽にpost

みたいなアプリのプロトタイプ作ろうと思ってTiPlatformConnectのYammer対応したという裏事情があったりします ^_^;