既存 Rails アプリに OAuth 認証を実装する
既存 Rails アプリに OAuth 認証を実装する
Doorkeeper を使った OAuth 2 の実装
Rails Tutorial で作成したアプリケーションに、REST API を実装したいな、と。
doorkeeper-gem_doorkeeper_ Doorkeeper is an OAuth 2 provider for Rails.
$ rails generate doorkeeper:install Running via Spring preloader in process 22456 create config/initializers/doorkeeper.rb create config/locales/doorkeeper.en.yml route use_doorkeeper =============================================================================== There is a setup that you need to do before you can use doorkeeper. Step 1. Go to config/initializers/doorkeeper.rb and configure resource_owner_authenticator block. Step 2. Choose the ORM: If you want to use ActiveRecord run: rails generate doorkeeper:migration And run rake db:migrate Step 3. That's it, that's all. Enjoy! ===============================================================================
[timestamp]_create_doorkeeper_tables.rb
なマイグレーションファイルが出来上がるので、以下の行を追加。
add_foreign_key :table_name, :users, column: :resource_owner_id
マイグレーション実行。
$ rails db:migrate == 20170719212201 CreateDoorkeeperTables: migrating =========================== -- create_table(:oauth_applications, {}) -> 0.0112s -- add_index(:oauth_applications, :uid, {:unique=>true}) -> 0.0028s -- create_table(:oauth_access_grants, {}) -> 0.0010s -- add_index(:oauth_access_grants, :token, {:unique=>true}) -> 0.0049s -- add_foreign_key(:oauth_access_grants, :oauth_applications, {:column=>:application_id}) -> 0.0000s -- create_table(:oauth_access_tokens, {}) -> 0.0008s -- add_index(:oauth_access_tokens, :token, {:unique=>true}) -> 0.0007s -- add_index(:oauth_access_tokens, :resource_owner_id) -> 0.0010s -- add_index(:oauth_access_tokens, :refresh_token, {:unique=>true}) -> 0.0014s -- add_foreign_key(:oauth_access_tokens, :oauth_applications, {:column=>:application_id}) -> 0.0000s -- add_foreign_key(:table_name, :users, {:column=>:resource_owner_id}) -> 0.0000s == 20170719212201 CreateDoorkeeperTables: migrated (0.0257s) ==================
config/initializers/doorkeeper.rb
の resource_owner_authenticator
メソッドを書き換える。(設定より規約、の Rails に設定が増えてしまった。)
resource_owner_authenticator do if (user_id = session[:user_id]) @user ||= User.find_by(id: user_id) else session[:forwarding_url] = request.fullpath redirect_to(login_url) end end
上記でフレンドリーフォワーディングにも対応できる。
(ログインしていないユーザーが OAuth 認可を取得しようとしたなら、ログインした後には自分のプロフィールページを表示するのではなく OAuth 認可ができる方がいいよね、というやつ)
これで rails s
して /oauth/applications
にアクセスすると、アプリケーション一覧画面が表示される。
New Application をクリックして必要な情報を入力すると OAuth ログインに必要な情報が作成され、確認できる。
Authorization code の取得までは可能。
ただ、開発環境で TLS 対応はしておらず動作確認できないのでここから先は Heroku 上で行う。
Heroku へのデプロイ
$ git push heroku $ heroku pg:reset DATABASE $ heroku run rails db:environment:set RAILS_ENV=production $ heroku run rails db:schema:load DISABLE_DATABASE_ENVIRONMENT_CHECK=1 $ heroku run rails db:seed
ここからは以下に沿って動作を確認する。
Testing your provider with OAuth2 gem · doorkeeper-gem_doorkeeper Wiki
$ irb >> require 'oauth2' => true >> client_id = 'hogehoge' => "hogehoge" >> client_secret = 'hogehoge' => "hogehoge" >> redirect_uri = 'urn:ietf:wg:oauth:2.0:oob' => "urn:ietf:wg:oauth:2.0:oob" >> site = "https://hogehoge.herokuapp.com" => "https://hogehoge.herokuapp.com" >> client = OAuth2::Client.new(client_id, client_secret, :site => site) => #<OAuth2::Client:0x00000001d8e428 @id="hogehoge", @secret="hogehoge", @site="https://hogehoge.herokuapp.com", @options={:authorize_url=>"/oauth/authorize", :token_url=>"/oauth/token", :token_method=>:post, :auth_scheme=>:request_body, :connection_opts=>{}, :connection_build=>nil, :max_redirects=>5, :raise_errors=>true}> >> client.auth_code.authorize_url(:redirect_uri => redirect_uri) => "https://hogehoge.herokuapp.com/oauth/authorize?client_id= hogehoge&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code" >> code = "hogehoge" => "hogehoge" >> token = client.auth_code.get_token(code, :redirect_uri => redirect_uri) => #<OAuth2::AccessToken:0x000000027e5d90 @client=#<OAuth2::Client:0x00000001d8e428 @id="hogehoge", @secret="hogehoge", @site="https://hogehoge.herokuapp.com", @options={:authorize_url=>"/oauth/authorize", :token_url=>"/oauth/token", :token_method=>:post, :auth_scheme=>:request_body, :connection_opts=>{}, :connection_build=>nil, :max_redirects=>5, :raise_errors=>true}, @auth_code=#<OAuth2::Strategy::AuthCode:0x00000001d7f838 @client=#<OAuth2::Client:0x00000001d8e428 ...>>, @connection=#<Faraday::Connection:0x00000001d7f4f0 @parallel_manager=nil, @headers={"User-Agent"=>"Faraday v0.12.1"}, @params={}, @options=#<Faraday::RequestOptions (empty)>, @ssl=#<Faraday::SSLOptions verify=true>, @default_parallel_manager=nil, @builder=#<Faraday::RackBuilder:0x00000001d7eff0 @handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp], @app=#<Faraday::Request::UrlEncoded:0x0000000205aeb8 @app=#<Faraday::Adapter::NetHttp:0x0000000205afa8 @app=#<Proc:0x0000000205b0e8@/usr/local/rvm/gems/ruby-2.3.1/gems/faraday-0.12.1/lib/faraday/rack_builder.rb:152 (lambda)>, @connection_options={}, @config_block=nil>>>, @url_prefix=#<URI::HTTPS https://hogehoge.herokuapp.com/>, @proxy=nil>>, @token="hogehoge", @refresh_token=nil, @expires_in=7200, @expires_at=1500699196, @options={:mode=>:header, :header_format=>"Bearer %s", :param_name=>"access_token"}, @params={"token_type"=>"bearer", "created_at"=>1500691996}>
AccessToken が取得できた!
その他
そもそも OAuth 2 じゃなくてよくね。。?(なんとなく OAuth 2 を選択したのがなんか浅はかだったような)
Doorkeeper の Gem はよくできてて簡単ですね。
- REST API の実装
- OAuth による上記 API の保護
と進めていく予定。