🐶

【Rails7, Sorcery】LINEログインの実装

2024/04/16に公開
自己紹介

もなかと申します。
プログラミング学習2年目の初心者です。
Ruby on Railsをメインに勉強しています。
実務は未経験です。
内容につきまして、間違いや不備がありましたらコメントで教えてください。

参考文献

https://github.com/Sorcery/sorcery/wiki/External
https://qiita.com/tarakish/items/a4c73104375878ad61c5
https://qiita.com/ICU1234/items/1a6c2e9729aa64a9858f
https://zenn.dev/yoiyoicho/articles/974c73ac75c100
https://qiita.com/kujira_engineer/items/ce8f0f7e025324afc6b6
https://blog.aiandrox.com/posts/tech/2020/03/29/

LINEログインの導入

今回、LINE Developerの開発者登録については省略させていただきます。無料で使えます。
https://developers.line.biz/console/

環境

Ruby 3.2.2
Rails 7.0.8
gem 'sorcery'

gemのインストール

gem 'omniauth-auth0'
gem 'omniauth-line'
gem 'omniauth-rails_csrf_protection'
bundle install

Externalのインストール

https://github.com/Sorcery/sorcery/wiki/External
sorceryで外部認証が行えるようにExternalのインストールを行います。

rails g sorcery:install external --only-submodules

以下が生成されます。

XXXXXX_sorcery_external.rb
class SorceryExternal < ActiveRecord::Migration[7.0]
  def change
    create_table :authentications do |t|
      t.integer :user_id, null: false
      t.string :provider, :uid, null: false

      t.timestamps              null: false
    end

    add_index :authentications, [:provider, :uid]
  end
end
rails db:migrate

モデルを生成します。
外部認証機能を追加する場合、通常は外部認証プロバイダーとの連携に使用する情報を格納するためのマイグレーションファイルは必要ありません。

rails g model Authentication --migration=false

サブモジュールの機能を追加します。

https://qiita.com/tarakish/items/a4c73104375878ad61c5
https://github.com/Sorcery/sorcery/wiki/External

config/initializers/sorcery.rb
Rails.application.config.sorcery.submodules = [:external]
#Here you can configure each submodule's features.
Rails.application.config.sorcery.configure do |config|
    (中略)
    # -- external -- 78行目辺り
    # What providers are supported by this app
    # i.e. [:twitter, :facebook, :github, :linkedin, :xing, :google, :liveid, :salesforce, :slack, :line].
    # Default: `[]`
    config.external_providers = %i[line]
    (中略) # 223行目辺り
    config.line.key = Rails.application.credentials.dig(:line, :channel_id)
    config.line.secret = Rails.application.credentials.dig(:line, :channel_secret)
    config.line.callback_url = 'http://localhost:3000/oauth/callback?provider=line'
    config.line.scope = 'profile'
    # config.line.bot_prompt = "normal"
      config.line.user_info_mapping = {name: 'displayName', email: 'userId'}

    (以下略)

    # -- external --
    user.authentications_class = Authentication
  end
end

config.line.user_info_mapping…名前通り、line認証を通して取得する情報(user_info)を、アプリ側でどのパラメータとして扱うか(mapping)の設定。

callback_urlの設定

config.line.callback_url…コールバックURLを設定。
開発・本番環境で違う設定が必要です。
GoogleやTwitterの認証と違い、LINEのチャネルにはコールバックURLを一つしか登録できないため、
確認したい環境に合わせて都度変更する必要があります。

sorcery.rb
# 開発環境
+ config.line.callback_url = 'http://localhost:3000/oauth/callback?provider=line'
sorcery.rb
# 本番環境
+   config.line.callback_url = 'https://本番環境のドメイン/oauth/callback?provider=line'

参考にした記事の通りにできなかったので、sorcery.rbに直接書き込む形にしました。

キーの設定

config.line.key…作成したプロバイダー(チャネル)のチャネルIDを設定
config.line.secret…作成したプロバイダー(チャネル)のチャネルシークレットを設定

credentials.yml.enc
line:
  channel_id: チャネルidの値
  channel_secret: チャネルシークレットの値

LINE DevelopersのコールバックURLの設定

下記を記載。

# 開発環境
http://localhost:3000/oauth/callback
# 本番環境
http://本番環境のドメイン/oauth/callback

ユーザー認証との紐付け

app/models/user.rb
class User < ActiveRecord::Base
+  has_many :authentications, :dependent => :destroy
+  accepts_nested_attributes_for :authentications
end
app/models/authentication.rb
class Authentication < ActiveRecord::Base
  belongs_to :user
end

OauthsControllerの作成

認証を処理するためのコントローラーを作成します。

app/controllers/oauths_controller.rb
class OauthsController < ApplicationController
   skip_before_action :require_login, raise: false

  # sends the user on a trip to the provider,
  # and after authorizing there back to the callback url.
  def oauth
    login_at(params[:provider])
  end

  def callback
    provider = params[:provider]
    if @user = login_from(provider)
      redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
    else
      begin
        @user = create_from(provider)
        # NOTE: this is the place to add '@user.activate!' if you are using user_activation submodule

        reset_session # protect from session fixation attack
        auto_login(@user)
        redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
      rescue
        redirect_to root_path, :alert => "Failed to login from #{provider.titleize}!"
      end
    end
  end

  #example for Rails 4: add private method below and use "auth_params[:provider]" in place of
  #"params[:provider] above.

  # private

  # def auth_params
  #   params.permit(:code, :provider)
  # end

end

viewへの表示

自身のルーティングを確認して記載してください。

app/views/layouts/application.html.erb
<%= link_to 'Login with Line', oauths_oauth_path(:provider => :line) %>

ngrokを使ってローカル環境をhttpsで公開する

コールバックURLにhttp://localhost:3000などのURLは使えません。
そのため、ngrokを使ってローカルで立ち上げたウェブアプリケーションを外部に公開します。
https://zenn.dev/yoiyoicho/articles/974c73ac75c100#ngrokを使ってローカル環境をhttpsで公開する
https://qiita.com/kujira_engineer/items/ce8f0f7e025324afc6b6

ファイルをダウンロード

ngrokのサイトでユーザー登録を行い、バイナリファイルをダウンロードします。
今回は手動でngrokをダウンロードして解凍する方法で行うので、brew install ngrok/ngrok/ngrokは必要ありません。

# intel macの方
unzip ~/Downloads/ngrok-v3-stable-darwin-amd64.zip

# apple siliconの方
unzip ~/Downloads/ngrok-v3-stable-darwin.zip

https://ngrok.com/

次のコマンドを実行して、認証トークンを追加します。

./ngrok config add-authtoken xxxxxxxxxxxxxxxxxxxxxxxx(あなたのauthtoken)

アプリをオンラインで開く

config/environments/development.rb に下記を記載し、hostを追加すれば動作できます。
許可したいホスト名には xxxxxxxx.ngrok.io の部分を追加してください。(httpsなどの部分は不要です。)

config/environments/development.rb
Rails.application.configure do
+ config.hosts << "許可したいホスト名"
end

うまくいかない場合や許可したいホスト名を何度も書きかえるのが面倒な人は下記のやり方を行ってみてください。

 config/environments/development.rb
Rails.application.configure do
+  config.hosts.clear
end

アプリを一時ドメインでオンラインにするためにサービスに転送します。

./ngrok http 3000

下記のように表示されます。

ngrok
K8s Gateway API support available now: https://ngrok.com/r/k8sgb

Session Status                online
Account                       (名前)
Version                       3.8.0
Region                        Japan (jp)
Latency                       32ms
Web Interface                 http://XXXX:XXXX
Forwarding                    https://XXXXXXXXXXXXXX.ngrok-free.app -> http://localhost:3000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

うまくいかないとき

400 Bad Request と表示される。

https://support.ec-force.com/hc/ja/articles/4407310334361-LINE-ID連携が正常に動作しない場合のよくある事例

LINEでログインのボタンを押した後にエラー。

./ngrok http 3000の画面上で

HTTP Requests
-------------
GET /                          403 Forbidden

https://qiita.com/kodai_0122/items/67c6d390f18698950440

403(Forbidden)エラー。

https://www.oro.com/semlabo/189/

LINEの名前が反映されなかった。

私はLINEログイン機能を実装してから、名前(displayName)が反映されるように行いました。
しかし、名前は変更されませんでした。
解決策として、そのuser_idを一度削除してから再度ログインを行うと正しく反映させることができました。

最後に

最後まで読んでいただいてありがとうございました。
不備等ありましたらコメント等お願いいたします。

Discussion