初めに
初学者です。
個人開発でRailsアプリにLINE連携ログインを導入した際の記録です。
アプリでLINEBOTと合わせてLINE連携ログインを利用したかったので導入しました。
deviseを使用して実装しています。
この記事で行なっている作業はこちらの記事で構築した環境で実施しています。
https://qiita.com/tkhero555/items/a1811369c59021077d62
アプリ「Puri.log」はこちら(2024/5/3時点でMVPリリース状態)
https://purilog-2a85943c9f18.herokuapp.com/
技術構成とバージョン
カテゴリ | 技術 |
---|---|
フロントエンド | javascript/Hotwire/bootstrap |
バックエンド | ruby3.3.0/rails7.1.3.2 |
データベース | PostgreSQL16.2 |
認証 | devise |
環境構築 | Docker / docker-compose |
CI/CD | Github Actions |
インフラ | heroku |
deviseの導入と初期設定
gem 'devise'を導入する。
gem 'devise'
バンドルインストールした後、deviseを実行して必要なファイルを作る。
docker compose run web bundle install
docker compose run web rails g devise:install
docker compose run web rails g devise User
生成されるマイグレーションファイルを確認してnameカラムを追加する。
# frozen_string_literal: true
class DeviseCreateUsers < ActiveRecord::Migration[7.1]
def change
create_table :users do |t|
## Database authenticatable
t.string :name
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
# t.integer :sign_in_count, default: 0, null: false
# t.datetime :current_sign_in_at
# t.datetime :last_sign_in_at
# t.string :current_sign_in_ip
# t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
db:migrateする。
LINEとdeviseを連携する
LINE developersでLINEログインの新しいチャネルを作成しておく。
gem 'omniauth-line'を導入する。
gem 'omniauth-line'
gem 'omniauth-rails_csrf_protection'
バンドルインストールとビルドする。
.envファイルにLINEログイン用の環境変数を追加する。
# LineBotで使用したチャンネルシークレットとトークン
LINE_CHANNEL_SECRET="LINEBOT用のチャネルのsecret"
LINE_CHANNEL_TOKEN="LINEBOT用のチャネルのトークン"
# 今回設定するチャンネルIDとシークレット
LINE_LOGIN_KEY='LINEログイン用チャネルのChannel ID'
LINE_LOGIN_SECRET='LINEログイン用チャネルのChannel Secret'
config/initializers/devise.rbで接続するLINEチャネルのIDとシークレットをENVを利用して設定する。
config.omniauth :line, ENV['LINE_LOGIN_KEY'], ENV['LINE_LOGIN_SECRET']
User.rbにomniauthの記述を追加する。
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: %i[line] # この1行を追加
end
omniauth_collbacks_controllerを作成する。
docker compose run web rails g controller omniauth_callbacks
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def line
basic_action
end
private
def basic_action
# 認証情報を取得
@omniauth = request.env["omniauth.auth"]
# 認証情報が存在している場合
if @omniauth.present?
# 認証情報のproviderとuidを元に、ユーザーを発見もしくは初期化する。
@profile = User.find_or_initialize_by(provider: @omniauth["provider"], uid: @omniauth["uid"])
# 保存したユーザー情報のemailが空白なら
if @profile.email.blank?
# 三項演算子 認証情報の[info][email]が存在する場合その値を代入 そうでない場合認証情報の中身を使って、一意のダミーemailアドレスを作っている
email = @omniauth["info"]["email"] ? @omniauth["info"]["email"] : "#{@omniauth["uid"]}-#{@omniauth["provider"]}@example.com"
# current_userが存在するならそのまま代入、しないならその場で認証情報から新しいユーザーを作成している。
@profile = current_user || User.create!(provider: @omniauth["provider"], uid: @omniauth["uid"], email: email, name: @omniauth["info"]["name"], password: Devise.friendly_token[0, 20])
end
# set_values(@omniauth)はuserモデルで定義されたメソッド
@profile.set_values(@omniauth)
# ログイン動作を実施する
sign_in(:user, @profile)
end
#ログイン後のflash messageとリダイレクト先を設定
flash[:notice] = "ログインしました"
# ここのリダイレクト先は後で自分のルーティングに応じて変更する
redirect_to expendable_items_path
end
# ダミーのemailアドレスを作成するメソッド
def fake_email(uid, provider)
"#{auth.uid}-#{auth.provider}@example.com"
end
end
ルーティングを設定する
devise_for :users, controllers: {
omniauth_callbacks: "omniauth_callbacks"
}
UserモデルにLINEログイン用のカラムを追加する。
docker compose run web rails g migration add_column_to_users
class ChangeColumnToUser < ActiveRecord::Migration[6.0]
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
end
end
Userモデルにメソッドを追加する。
# social_profilesの中身を順番に取り出して、指定したproviderと一致する最初のsocial_profileを返す
def social_profile(provider)
social_profiles.select { |sp| sp.provider == provider.to_s }.first
end
# omniauthから受け取った情報で、インスタンスの属性を設定する。
def set_values(omniauth)
# omniauthのproviderとuidのどちらかが既存の値と異なる場合、この時点でreturnしてメソッドを終了する。
return if provider.to_s != omniauth["provider"].to_s || uid != omniauth["uid"]
# omniauthのcredentialsを取り出す
credentials = omniauth["credentials"]
# omniauthのinfoを取り出す
info = omniauth["info"]
# さっき取り出したcredentialsからrefresh_tokenを取り出す
access_token = credentials["refresh_token"]
# さっき取り出したcredentialsからsecretを取り出す
access_secret = credentials["secret"]
# 最後にcredentialsをjson化しておく
credentials = credentials.to_json
# さっき取り出したinfoからnameを取り出す
name = info["name"]
end
# 引数で受け取ったraw_infoをjson化してインスタンスのraw_infoに格納する
def set_values_by_raw_info(raw_info)
self.raw_info = raw_info.to_json
self.save!
end
LINE developersでコールバックのurlを設定する
ngrokを起動して外部からローカルサーバーにアクセスできるURLを確保
ngrokの導入と設定はこちらの記事で実施済み
https://qiita.com/tkhero555/items/4af4c7cd48a757974685
ngrok http 3000
ルーティングを確認して、ngrokのurl + omniauth_callbacks_controllerのlineアクションのルーティングをLINEログインのwebhookに設定する。
上手く行っていればdeviseのloginページにSign in with Lineのボタンができており、クリックするとLINE連携ログイン画面へ遷移するようになっている。
参考記事等
https://qiita.com/prg_mt/items/b3238ebfae1a3df67cab
https://zenn.dev/yoiyoicho/articles/974c73ac75c100