LoginSignup
17
18

More than 5 years have passed since last update.

【Ruby on Rails】DeviseなしのUserモデルにOauth認証を追加する方法

Last updated at Posted at 2019-04-09

Oauth認証とは

Open Authorization 認証の略です。読み方は「オーオース」らしい。
ざっくりいうとTwitterやFacebookのアカウント情報でログインできるようになります。
アイコン画像も取ってこれるので、ユーザーとしては登録の手間がかなり省けて便利です。

まずはAPIを取得する必要がある。

こちらを参考にDeveloperとして登録します。しかし、Describe in your own words what you are buildingの欄のみリンクと違い、4つの質問に一つ一つ答えていく形式に変わっています。(2019年4月10日現在)

developer3.png

大まかに日本語に訳すと、以下の事柄について聞かれています。
すべて合わせて、300文字以上書く必要があります。

1.どのような目的やケースでツイッターのAPIを使うのか
2.ツイートやユーザーなどを分析するつもりかどうか。もしするなら、その方法や技術と詳細を記述。
3.ツイート、リツイート、リンクを含んだ使い方をするかどうか。もしするなら、ユーザーやコンテンツをやりとりする方法を記述。
4.どのようにツイッターの情報が表示されるのか。もしツイッターからコンテンツを表示するなら、アプリのどこにどのように表示されるのかを記述(それぞれのツイートやツイッターのコンテンツが表示されるのか、それともまとめた情報が表示されるのか)

Developerの登録が終わったら、こちらにいき、右上の「Create an app」からAPIを使うアプリを登録します。
「App name」や「Website URL」は特に問題ないですが、Callback URLsに関してはURLが2つ以上登録されていないと正しく動作しません。
ローカル環境の場合は以下の2つのURLを登録します。

http://127.0.0.1:3000/auth/twitter/callback
http://localhost:3000/auth/twitter/callback

twittercallback.png

また本番環境のときには、localhost:3000や127.0.0.1:3000の部分をドメイン名に書き換えたURLを一つ追加すればOKです。

次にKeys and tokensからConsumer API keysをを取得します。

twitterconsumer.png

このAPI KeyとAPI secret keyを後で使用します。
Access token & access token secretについては認証やツイートを取得するだけであれば必要ありません。

gemのインストール

各種gemをインストールしていきます。

twitter認証用のgem

Gemfile
gem 'omniauth'
gem 'omniauth-twitter'

先ほどのConsumer API keysはGitHubに上げたくないので、環境変数に入れます。
今回は.bash_profileなどには入れず、gemで管理したいと思います。

Gemfile
gem 'dotenv-rails'

bundleします。

設定

まずは環境変数の設定をします。
直下の.env(なければ作成)に以下を追記します。

.env
TWITTER_CONSUMER_KEY = (先ほど取得したAPI Key)
TWITTER_CONSUMER_SECRET = (先ほど取得したAPI secret key)

.env.gitignoreに追加するのを忘れないようにしてください。

route.rbに以下を追記します

route.rb
get 'auth/:provider/callback', to: 'sessions#create'

次にconfig/initializers/omniauth.rbを作成し、以下を設定

config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
    provider :twitter, ENV['TWITTER_CONSUMER_KEY'], ENV['TWITTER_CONSUMER_SECRET'],
end

実装

次にuserモデルにuid, provider、もしなければimageのためのカラムも追加します。
providerで何のサービスかを判断し、uidでどのユーザーかを識別しています。

add_columns_to_users.rb
class AddColumnsToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :uid, :string
    add_column :users, :provider, :string
    add_column :users, :image_url, :string
  end
end

rails db:migrate後、Userモデルには以下を追記します。

user.rb
  def self.find_or_create_from_auth(auth)
    provider = auth[:provider]
    uid = auth[:uid]
    name = auth[:info][:name]
    image = auth[:info][:image]

    self.find_or_create_by(provider: provider, uid: uid) do |user|
      user.name = name
      user.image_url = image
    end
  end

self.find_or_create_by(provider: provider, uid: uid) do |user|
でcreateが行われていた場合に検証やコールバックが行われるので適時修正する必要があります。

自分の場合は

user.rb
  before_save { self.email.downcase! }
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                    uniqueness: { case_sensitive: false }
  has_secure_password

user.rb
  before_save :email_downcase, unless: :uid?
  validates :name, presence: true, unless: :uid?, length: { maximum: 50 }
  validates :email, presence: true, unless: :uid?, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                    uniqueness: { case_sensitive: false }
  has_secure_password validations: false

  private

  def email_downcase
    self.email.downcase!
  end

のように修正することで上手くいきました。unless: :uidを使用するときには処理内容をメソッドとして切り分けないとsyntax errorになります。

次にsessions_controllersを以下のように修正します。

sessions_controller.rb
  def create
    auth = request.env['omniauth.auth']
    if auth.present?
      user = User.find_or_create_from_auth(request.env['omniauth.auth'])
      session[:user_id] = user.id
      redirect_to user
    else
      (従来のログイン処理)
    end
  end

次に画像の表示の仕方です。
自分の場合はメールアドレスに対応してgravatarのアイコンが表示される実装になっていました。
(プログラミングスクールやRailsチュートリアルではよくある実装だと思います)
そこで、画像を表示するヘルパーを以下に修正

users_helper.rb
module UsersHelper
  def icon_url(user, options = { size: 80 })
    if user.email.present?
      gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
      size = options[:size]
      return "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
    else
      return user.image_url
    end
  end
end

最後にビューの実装です。

<%= link_to "Twitterアカウントでログイン", "/auth/twitter" %>

まとめ

はまるポイントとしてはCallback URLsが複数必要なこととcreateで検証やコールバックでつまづくところでしょうか。同じ要領で他のSNSのOauth認証もやっていきたいと思います。

17
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
18