爆速ッ!! gem omniauth-google-oauth2 で認証させる

# Railsでユーザ認証させる
鉄板のDevise + Omniauthの組み合わせですが、意外とomniauth-google-oauth2に関する記事は少なそうだったので、備忘録+写真で解説してみます。

# Let's Try!
## まずはGoogle Developers Consoleで登録
https://console.developers.google.com/project
<img width="1680" alt="スクリーンショット 2015-12-15 20.18.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/b19c9d7e-a343-b235-4947-a511ce5583fa.png">

プロジェクトを作成をクリックし、

<img width="569" alt="スクリーンショット 2015-12-15 20.22.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/ce246365-ae53-3300-5767-5c7988a4870e.png">

よしなにプロジェクトを作成します。

## 使用するAPIの設定
今回はあくまで「ユーザ認証」を行いたいため、不要なAPIの利用は解除していきます。
<img width="341" alt="スクリーンショット 2015-12-15 20.22.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/738b1dd1-07c2-5dd0-0244-9e874c41df3e.png">

サイドバーから、API Manager > 概要 を選択し、

<img width="607" alt="スクリーンショット 2015-12-15 20.22.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/9b4258e0-a463-7957-633a-fc185a0eac92.png">

Enable APIs (7) タブを選択、

<img width="581" alt="スクリーンショット 2015-12-15 20.22.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/8b373db9-6f99-568e-2df2-d7c30f735a37.png">

Google+ APIを除いて無効にしておきます。(ムダなAPIは無効に！)

## 認証情報と同意画面の設定
<img width="331" alt="スクリーンショット 2015-12-15 20.27.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/975d3fe9-9a24-dab0-d62c-b82b12f0af41.png">
再びサイドメニューから、今度は認証情報を選び、

<img width="731" alt="スクリーンショット 2015-12-15 20.29.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/f2c142f2-b17d-7e54-8b41-ae8d78f8adbc.png">

OAuth 同意画面タブへ移動します。
ココで同意画面を作っておこないと、認証情報追加時にケラれます

<img width="503" alt="スクリーンショット 2015-12-15 20.34.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/20fd2777-af7a-73ae-a41b-02437267c4cd.png">

新しい認証情報を追加する際は、"OAuth クライアントID"を選択。

<img width="752" alt="スクリーンショット 2015-12-15 20.36.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/54152446-a6ed-8c71-d590-662c1df28f37.png">

アプリケーションの種類は、ウェブアプリケーション。名前を入力します。
承認済みのリダイレクトURIに、``http://localhost:3000/users/auth/google/callback``と入力しておいてください。

<img width="599" alt="スクリーンショット 2015-12-15 20.46.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/24a0e250-4363-62a5-79e6-d2e0dcb561f7.png">

クライアントID、クライアントシークレットが発行されるので、どこかに控えておいてくださいね。

## Railsプロジェクト作成

```bash
$ rails new openidtest
```
テスト用のRailsプロジェクトを作成します。

## Gemfileに追加

```rb:Gemfile
...
gem 'devise'
gem 'omniauth'
gem 'omniauth-google-oauth2'
...
```

```bash:openidのroot上で
$ bundle install
```

## Deviseの設定

```bash
# Deviseの初期化
$ rails g devise:install
```
すると、以下のメッセージが出てきます。どうしてもうまくいかねぇ...というとき、このメッセージに立ち返ってみるといいですね。

```
Running via Spring preloader in process 23652
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================
```

## ユーザ認証情報を保持するテーブルを作る
作業は続きます。

```bash
# ユーザ認証用のテーブル作成
$ rails g devise user
```
これで、ユーザ認証に関する情報を保持するテーブルが生成されます。
新たに追加されたmigrationファイルに、ユーザ情報を保持しておくカラムを追加しておきましょう。

ユーザ情報をいちいちGoogleに問い合わせるのはナンセンスなので、
アプリケーションで必要になりそうなデータは、例えば初回ログイン時などにデータを取得して保存しておくなどが良いですね。

```rb:migrationファイル
class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
...
      t.string :users, :provider
      t.string :users, :uid
      t.string :users, :token
      t.string :users, :meta
...
    end
  end
end
```

```bash
# migrationファイルに基づいてテーブルを作る
$ rake db:migrate
```

土台は出来ましたね。

## Model修正

```rb:app/models/user.rb
class User < ActiveRecord::Base
  devise :trackable, :omniauthable, omniauth_providers: %i(google)

  protected
  def self.find_for_google(auth)
    user = User.find_by(email: auth.info.email)

    unless user
      user = User.create(name:     auth.info.name,
                         provider: auth.provider,
                         uid:      auth.uid,
                         token:    auth.credentials.token,
                         password: Devise.friendly_token[0, 20],
                         meta:     auth.to_yaml)
    end
    user
  end
end
```

``:trackable, :omniauthable``だけでOKです。deviseに新たに機能を持たせたいときは、そのとき新たに追記する方がスマートだと思います。今回は、とりあえずログインすることが目的なので、これでよい！

また、``def self.find_for_google(auth)``は、コールバックを受けた時にユーザが既にアプリケーションの中で認知されているかどうかを判断するメソッドです。後で使います。

## config修正

```rb:config/initializers/devise.rb
Devise.setup do |config|
  require 'devise/orm/active_record'
  config.omniauth :google_oauth2,
                  ENV['GOOGLE_APP_ID'], # 環境変数に先ほど控えたクライアントIDを入れておく
                  ENV['GOOGLE_APP_SECRET'], # 環境変数に先ほど控えたシークレットを入れておく
                  name: :google,
                  scope: %w(email) 
end
```

It's Simple!!
scopeについて、デフォルト(ここに記述しない状態)だとemailとprofileになります。ユーザ認証のための必須ではないため、emailだけにしちゃいましょう


## ログインボタンを設置するページ作る

```bash
$ rails g controller home index
```

```erb:app/controllers/views/home.html.erb
<%= link_to 'Signin with Google', user_omniauth_authorize_path(:google) %>
```

ビューの準備完了しました。

## routes.rbの書き換え

```rb:config/routes.rb
Rails.application.routes.draw do
  get 'home/index'
  
  # devise_for :users <- コメントアウトするか消しちゃいます
  devise_for :users, controllers: {
      omniauth_callbacks: "users/omniauth_callbacks"
  }
...
```

## omniauth_callbacks_controller.rbを作成

``app/controllers/users``ディレクトリを作成して、``omniauth_callbacks_controller.rb``というコントローラーを作成します。

```rb:omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def google
    @user = User.find_for_google(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
      sign_in_and_redirect @user, event: :authentication
    else
      session['devise.google_data'] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end
```

## サーバ起動
```bash
$ rails s
```
で、サーバを起動し、
http://localhost:3000/home/index にアクセスすると...

<img width="348" alt="スクリーンショット 2015-12-15 21.34.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/12156978-1c2f-1384-88f9-8c759d6cd14b.png">

の文字が...！早速押してみましょう！

<img width="400" alt="スクリーンショット 2015-12-15 21.35.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/d9fe0609-b19d-8097-a742-07e89bea8d0b.png">

どきどき...

<img width="522" alt="スクリーンショット 2015-12-15 21.36.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/813ef5c3-0258-a039-5e6d-b67efc9a5131.png">

キタ！

<img width="769" alt="スクリーンショット 2015-12-15 22.08.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/3377/945fbfb4-df0e-91ea-8898-2631faaaf078.png">

来ましたー！routes.rbでログイン後に遷移する先を記述していないのでrootに行ってますね。ログイン後、viewなどで``current_user.email``などを表示させてみれば、ログインしているユーザのemailアドレスが表示されるかと思います。
動かん！などのコメント、お待ちしております！