takumiのエンジニア技術ブログ

takumiのエンジニア技術ブログ

未経験からエンジニアを目指しています!技術定着の為にこのブログにアウトプットしていきます!気軽にコメント等いただけるとありがたいです!

Deviseなしで、Twitterログインを実装する(OAuth認証)

f:id:golikyua:20200109135521j:plain


 

 

現在作成しているアプリケーションにdeviseなしでtwitteログインを実装したので、アウトプットします。

OAuth認証という認証により、twitter,facebook等のユーザー情報でログインできるよにしま。

OAuth認証については以下の記事が分かりやすかったので、一度読んでみてください。

https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be

 

ruby 2.5.7

rails 5.2.3

 

 

やること

・twitterAPIを取得する。

・gemのインストール

・ルーティングの設定、APIキーの設定、OAuth認証の設定

twitterログインを実装

 

 

●twitterAPIを取得する。

twitterAPIの取得は以下の記事を参考させて頂き取得できました。

https://digitalnavi.net/internet/3072/

 

 

●gemのインストール

Gemfile

#twitter認証の為のgem
gem 'omniauth' gem 'omniauth-twitter'
#APIキーをGitHubに上げな為に環境変数に入れます。このgemは.envファイルから環境変数をロードする為のgemです。 gem 'dotenv-rails'

※APIキーをGitHub上に上げない方法は以前ブログに書いたので参考にしてみてください。

https://golikyua.hatenablog.com/entry/2019/12/02/135230

 

$bundle install

 

 

 

 

 

 ●ルーティングの設定、環境変数の設定、OAuth認証の設定

 

ルーティングの設定

routes.rb

Rails.application.routes.draw do

 ・・・
  
  get 'auth/:provider/callback', to: 'sessions#create'

 ・・・

end

今回はログイン機能をsessionsコントローラーのcreateアクションで実装したので、上のようにルーティングを設定しました。

 

 

 

環境変数の設定

.env

TWITTER_KEY="取得したAPI key"
TWITTER_SECRET="取得したAPI secret key"

これでローカル環境で、APIキーを使用することができますが、本番環境ではまだ使用できません。

 

自分の場合、アプリケーションをherokuにデプロイしていたので、heroku側でも環境変数を設定します。

 

コンソールで以下の設定を行います。

$ heroku config:set TWITTER_SECRET="取得したAPI key"
$ heroku config:set TWITTER_SECRET="取得したAPI secret key"

 

以下のコマンドで設定されている環境変数一覧が確認できるので、設定されているか確認してみましょう。

$ heroku config

 

 

OAuth認証の設定

config/initializers/omniauth.rbを作成し、以下を記入する。

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end

 

 

 

twitterログインを実装

 

 userモデルに以下のカラムを追加します。

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.rb内に以下のメソッドを追加します。

class User < ApplicationRecord

・・・

  def self.find_or_create_form_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

end

自分の場合これだけでログインしようとしたら、バリデーションに引っかかってログイン出来なかったので、バリデーションを変更します。

 

class User < ApplicationRecord

  validates :name, presence: true, unless: :uid?, length: { maximum: 30 }
  validates :email, presence: true, unless: :uid?, uniqueness: true, length: { maximum:255 },
                format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.freeze }

  validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,30}+\z/i }, length: { in: 8..30 }, unless: :uid?
  has_secure_password validations: false
  has_one_attached :image, dependent: :destroy
  has_many :posts, dependent: :destroy
  has_many :favorites, dependent: :destroy
  has_many :favorite_posts, through: :favorites, source: 'post'
  has_many :reviews, dependent: :destroy

 ・・・

end

 自分の場合nameカラム、emailカラム、passwordカラムにunless: :uid?を追加したら、バリデーションに引っかからなくなりました。

 

もしバリデーションに引っかかってログイン出来ない状態だったら、コメントアウトを使ってどこで引っかかっているか確認してみるといいと思います。

 

続いてsessionsコントローラーの設定を行います。

app/contorllers/sessions_controller.rb

class SessionsController < ApplicationController

・・・

  def create
    auth = request.env['omniauth.auth']
    if auth.present?
      user = User.find_or_create_form_auth(request.env['omniauth.auth'])
      session[:user_id] = user.id
      flash[:success] = "ユーザー認証が完了しました。"
      redirect_to user
    else
      @user = User.find_by(email: params[:session][:email])
      if @user && @user.authenticate(params[:session][:password])
        log_in @user
        flash[:success] = "ログインしました"
        redirect_to @user
      else
        flash.now[:danger] = "ログインに失敗しました"
        render 'new'
      end
    end
  end

 ・・・

end

ポイントは if文で、twitterログインと通常のログインを分けることです。これをやらないとエラーが発生します。(だいぶ苦労しました。)

 

最後に、ログインする為のビューを設定します。

app/views/sessions/new.html.erb

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

 

これで上手く行くと思います。