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

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

RubyGem: OAuthSimple 0.1.0.pre を公開しました

Ruby

Ruby でクライアント側の OAuth 認証 (OAuth 1.0) を使おうとすると Ruby OAuth gem とかを使うことになると思うんですが、たいていの OAuth ライブラリって気軽さに欠けるような気がするんですよね。 OAuth 認証をばりばり使うような場面ならライブラリの使い方を学習するべきだと思いますが、「ちょっと TwitterAPI を叩きたい」 というような場合にはもっと手軽に使えるものが欲しいですよね。 (もしかしたら既にあるのかな。。 )

というわけで Net::HTTP クラス に OAuth 認証の機能を加えたサブクラス OAuthSimple::HTTP を含むライブラリを作りました。 まだ機能的には完全じゃないですけど個人的に使うにはまあいいかなって感じなので pre 版として公開しました。

動作環境とインストール方法

Ruby 1.9.3 で使えることは確認しました。 1.8 系だと使えません。

インストールは gem コマンドを使って行うことができます。

$ gem install oauth_simple --pre

まだ pre 版なので --pre オプションが必要です。

OAuthSimple::HTTP の使い方

OAuthSimple::HTTP クラスは Net::HTTP クラスのサブクラスで、OAuth 認証をサポートします。 OAuthSimple::HTTP オブジェクトを生成した後に、use_oauth メソッドを使って OAuth 認証機能を使うことを指定し、set_oauth_client_credentials メソッドなどを使って OAuth 認証に必要な設定を行います。 その後は Net::HTTP オブジェクトを使うときと同じようにリクエストを投げると、勝手に OAuth 認証してくれます (現在は Authorization Header にプロトコルパラメータを付けてリクエストを投げるようになっています)。

以下に Twitter API を使う例を示します。 (Twitter の API については REST API Resources | Twitter Developers を見てください。)

require 'oauth_simple'

# OAuth の client credentials と user credentials
client_credentials = [
  'YOUR_CONSUMER_KEY',
  'YOUR_CONSUMER_SECRET',
]
token_credentials = [
  'YOUR_ACCESS_TOKEN',
  'YOUR_ACCESS_TOKEN_SECRET',
]

# OAuthSimple::HTTP は Net::HTTP のサブクラスで、Net::HTTP と同じようにインスタンス化できます
http = OAuthSimple::HTTP.new( 'api.twitter.com' )

# OAuth 認証に関する設定を行います
http.use_oauth = true                                    # OAuth 認証を使うようにする
http.set_oauth_client_credentials( *client_credentials ) # Client credentials を設定
http.set_oauth_user_credentials( *token_credentials )    # Token credentials を設定
http.set_oauth_signature_method( 'HMAC-SHA1' )           # Signature メソッドの設定
                                                         #   現在は 'HMAC-SHA1' にのみ対応

# 後は Net::HTTP オブジェクトを使用する場合と同じようにリクエストを投げます
#   自動的に OAuth 認証を行ってくれます
http.start do |http|
  path = '/1/statuses/mentions.json'
  http.request_get( path ) do |res|
    if res.code == '200'
      $stdout << res.body << "\n" # 実際は res.body を JSON 文字列としてパースして情報を取り出す
    else
      $stderr << "error\n"
      p res.body
    end
  end
end

上のような方法だと OAuthSimple::HTTP オブジェクトを生成するごとに OAuth のパラメータ設定をしなければいけないという問題があります。 そこで、以下のように OAuthSimple::HTTP クラスのサブクラスを生成し、デフォルトの OAuth パラメータを持たせることができるようにもなっています。

require 'oauth_simple'

# OAuth の client credentials と user credentials
client_credentials = [
  'YOUR_CONSUMER_KEY',
  'YOUR_CONSUMER_SECRET',
]
token_credentials = [
  'YOUR_ACCESS_TOKEN',
  'YOUR_ACCESS_TOKEN_SECRET',
]

# OAuth 機能をもつ Net::HTTP のサブクラス (OAuthSimple::HTTP)
# をサブクラス化して, デフォルトの OAuth パラメータを持たせる
MyHTTP = OAuthSimple::HTTP.create_subclass_with_default_oauth_params()
MyHTTP.set_default_oauth_client_credentials( *client_credentials ) # デフォルトの Client credentials を設定
MyHTTP.set_default_oauth_user_credentials( *token_credentials )    # デフォルトの Token credentials を設定
MyHTTP.set_default_oauth_signature_method( 'HMAC-SHA1' )           # デフォルトの Signature メソッドの設定
                                                                   #   現在は 'HMAC-SHA1' にのみ対応

# 後は, 上で生成した MyHTTP を Net::HTTP と同じように使ってリクエストを投げます
http = MyHTTP.new( 'api.twitter.com' )
http.start do |http|
  path = '/1/statuses/mentions.json'
  http.request_get( path ) do |res|
    if res.code == '200'
      $stdout << res.body << "\n" # 実際は res.body を JSON 文字列としてパースして情報を取り出す
    else
      $stderr << "error\n"
      p res.body
    end
  end
end

どういう場合に使えるか

上で見たように、OAuth のパラメータさえ与えてしまえば後は Net::HTTP と同じように使えるので、書き捨てのスクリプトでちょっと OAuth 認証が必要な API を叩きたい、という場合などに便利だと思います。

不完全です

pre 版ってことからもわかるように不完全で、例えば対応している signature メソッドは HMAC-SHA1 だけであるとか、request_oauth_temp_credentials と request_oauth_token_credentials が POST メソッドにしか対応してないとか、OAuth パラメータをサーバーに渡す方法として authorization header の値として渡す方法しかサポートしてないとか、そういう問題があります。 そのうち対応したいなーとは思いつつ自分が使う分には困ってないのでいつになるやら、って感じです。 改造したい人は github のコードを適当にいじってください。

あんまり設計が綺麗じゃないので設計に関しての助言なども頂けると嬉しいです。

付録: Token Credentials の取得

Twitter に関して言えば、現在は My applications | Twitter Developers でアプリケーションの登録をすれば自分の Token credentials (access token と access token secret) が表示されるので、それをそのまま使えばよいです。

しかし、自分で Token credentials を取得しないといけない web サービスもあると思います。 そういうときには

OAuthSimple#request_oauth_temp_credentials メソッドと OAuthSimple#request_oauth_token_credentials メソッドが使用できます。

# coding: UTF-8

require 'net/https' # if you use ssl
require 'oauth_simple'

# OAuthSimple::HTTP is a subclass of Net::HTTP
http = OAuthSimple::HTTP.new( 'api.twitter.com', 443 )

# SSL setting
http.use_ssl     = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER # 認証モードをセット

# OAuth setting (this feature is provided by OAuthSimple::HTTP)
http.use_oauth = true
http.set_oauth_client_credentials( 'YOUR_CLIENT_CREDENTIALS', 'YOUR_CLIENT_SECRET' )
http.set_oauth_signature_method( 'HMAC-SHA1' ) # at this time, only 'HMAC-SHA1' is supported

# connection start
http.start() do |http|

  # Temporary Credentials を取得 (取得した credentials は自動的に http オブジェクトにセットされる)
  token, secret = http.request_oauth_temp_credentials( '/oauth/request_token', 'oob' ) do |res_failed|
    # ステータスコード 200 以外が返ってきたらこのブロックがよばれる
    raise res_failed.body
  end

  # リソースオーナーによる認証 (利用者に認証ページで認証してもらい, verifier を入力してもらう)
  puts "https://api.twitter.com/oauth/authorize?oauth_token=#{OAuthSimple::HelperFunctions.enc_perenc(token)} にてアプリケーションを認証し, " + 
       'verifier を入力してください'
  $stdout << 'verifier : '
  verifier = $stdin.gets.chomp

  # Token Credentials を取得 (取得した credentials は自動的に http オブジェクトにセットされる)
  token, secret = http.request_oauth_token_credentials( '/oauth/access_token', verifier ) do |res_failed|
    # ステータスコード 200 以外が返ってきたらこのブロックがよばれる
    raise res_failed.body
  end

  # 変数 token と secret の中に Token credentials が入っているので, 保存が必要なら保存する

  # あとは先の例と同じように認証が必要なリソースにアクセスして使用する
  http.request_get( '/1/statuses/home_timeline.json?include_entities=true' ) do |res|
    # ... 省略 ...
  end

end