【画像付き】RailsでDeviseを利用してLINEログイン機能を実装

## はじめに

自作アプリでLINEBotを作成する際にLINEログイン機能を実装しました。

実装するに当たって様々な記事を参考にさせて頂きましたが, 記事によって記述が異なったり, ここはもう少し簡潔に書けるのでは？と思ったり, 記事通りに書いてもエラーが出たり, そもそも記事が古かったりで苦労しました。。

今後また実装する時に自分の記事さえ見れば導入できるように画像付きでまとめていきたいと思います！

基本的にRailsを想定していますが, LINE Developersの登録などはRails以外の言語でも参考になる部分があるかと思いますので, 少しでも参考になれば幸いです😄


## 1. Railsアプリを作成

- 以下の前提で進めていきます。（アプリやコントローラー名は任意の名前にして下さい）
- postgresqlに設定していますが, データベースはお好みで。

```zsh:ターミナル
rails new linelogin_sample -d postgresql
rails db:create
rails g controller homes index
```

``` config/routes.rb
Rails.application.routes.draw do
  root 'homes#index' 
end
```

ここまで出来たら `rails s` でサーバーを起動して http://localhost:3000 にアクセスし, 動作確認を行ってみて下さい。エラーが表示されていなければOKです！


## 2.Deviseを導入
LINEログイン機能の前に, まずはDeviseでログイン機能を実装していきます。

### 2-1.Gemfileの編集とインストール

```none:Gemfile
# ログイン機能
gem 'devise'
```
Gemfileを編集したらターミナルで `bundle install` を実行



### 2-2.Deviseをインストール
【公式】 [plataformatec/devise](https://github.com/plataformatec/devise)

```zsh:ターミナル
rails g devise:install
rails g devise User
rails db:migrate
```
（※ userの箇所は，任意のモデル名でOKです）

問題がなければ `rails s` でサーバーを立ち上げ，http://localhost:3000/users/sign_in にアクセスすると，ログイン画面が表示されます。
（すでにサーバーを起動している場合は再起動して下さい。）

![スクリーンショット 2020-10-21 16.55.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/4557fdb9-58ae-2bfe-040d-ae8fe910a293.png)


## 3.LINE Developersに登録

LINEログイン機能を実装するには LINE Developersに登録する必要があります。
まだ登録されてない方はこちらのURL ( https://developers.line.biz/ja/ ) からログイン画面に遷移し, LINEの登録時に設定したメールアドレスとパスワードでログインします。



登録が完了するとこのような画面が表示されるので, LINEログインを選択し, `今すぐはじめよう` というボタンをクリックしてください。
![スクリーンショット 2020-10-21 17.04.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/76381a2f-3cc1-80e9-d48b-6222baf6ee6e.png)

`今すぐはじめよう` をクリックすると新規プロバイダーを作成する画面が出てきますので, 必要な項目を入力し, プロバイダーを作成してください。

例えば, アンケートBotというアプリにLINEログイン機能を導入する場合は画像のように入力していきます。

![スクリーンショット 2020-10-21 17.30.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/a956dc9f-1d68-5dae-cb4f-08fd2f368eff.png)

![スクリーンショット 2020-10-21 17.30.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/e089ac6c-1fd0-1369-a80a-85bf2cb04edb.png)


![スクリーンショット 2020-10-21 17.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/1ac0fe91-5454-2fc0-cab8-05b3e5b4c12c.png)

上記はあくまで一例です。

プロバイダー名, チャネルアイコン, チャネル名, アプリタイプなどは任意のものにしてください。


## 4.LINEログイン機能を導入
LINE Developersで新規プロバイダーを作成したら, いよいよLINEログイン機能を実装していきます！

### 4-1.Omniauthのインストール
Gemfileに以下を追加し, `bundle install` を実行。

```:Gemfile
gem 'omniauth-line'
gem 'omniauth-rails_csrf_protection'
```


### 4-2.環境変数を設定
次にChannel IDとChannel Secretの設定を行います。 
今度はGemfileに以下のgemを追加し, `bundle install` を実行してください。

```none:Gemfile
gem 'dotenv-rails'
```

gemを追加したら, アプリのルート配下に `.env` ファイルを作成し, 以下の2つを追加してください。

```none:.env
LINE_KEY='自身のChannel ID'
LINE_SECRET='自身のChannel Secret'
```
▼環境変数の確認
![スクリーンショット 2020-10-21 22.13.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/c007332f-e31d-a0aa-7347-856e27163377.png)

![スクリーンショット 2020-10-21 22.14.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/e6a86389-0532-0ec1-2d54-2e6ddf593091.png)


【注意！】
このファイルを公開してしまうと悪用されてしまう可能性があるので, 必ずGitの管理下から外してください。
`.gitignore` に以下を追加

```:.gitignore
/.env
```

### 4-3.DeviseとLINEログインの設定
次にDeviseの設定ファイルにLINEログインの設定を行います。

- `devise.rb` に以下を追加

```devise.rb
config.omniauth :line, ENV['LINE_KEY'], ENV['LINE_SECRET']
```

- `user.rb` に `:omniauthable` と `omniauth_providers: %i[line]` を追加

```user.rb
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
```

（TwitterやFacebookログインなども導入する場合は `%i[line]` の配列に追加してください。
　例： `:omniauth_providers: %i[line twitter facebook]`）

### 4-4.コントローラーの設定

- omniauth_callbacks_controllerを作成します。

```zsh:ターミナル
rails g controller omniauth_callbacks
```

【注】OmniAuthのバージョンが原因でエラーが出ることがあります。

▼バージョンエラーが出た場合の対処

```:Gemfile
gem 'omniauth', '~> 1.9.1'
```

Gemfileに上記のコードを追加し, ターミナルで `bundle update`

`bundle update` でomniauthのバージョンが変わったのを確認したら,  `bundle install` を実行。
再度 `rails g` コマンドでコントローラーを作成して下さい。


- 以下を修正

```omniauth_callbacks_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def line; ; end
end
```

### 4-5.ルーティングの設定

- 以下のようにルーティングを設定します。

```routes.rb
devise_for :users, controllers: {
  omniauth_callbacks: "omniauth_callbacks"
}
```

ルーティングを `rails routes` で確認し、

```
user_line_omniauth_authorize GET|POST /users/auth/line(.:format)               omniauth_callbacks#passthru
user_line_omniauth_callback GET|POST /users/auth/line/callback(.:format)       omniauth_callbacks#line
```

このような表示がされていたらルーティングの設定は完了です！

### 4-6.モデルの変更
DeviseでUserモデルを作成しているのでそのままUserモデルに変更を加えてLINEログインができるようにしたいと思います。

- 以下のコマンドでマイグレーションファイルを作成

```zsh:ターミナル
rails g migration add_column_to_users
```

- 作成されたマイグレーションファイルに以下を追加

```db/migrate/20201022073739_change_column_to_user.rb
class ChangeColumnToUser < ActiveRecord::Migration[6.0]
  def change
　　# 以下を追加
    add_column :users, :provider, :string
    add_column :users, :uid, :string
    add_column :users, :name, :string
  end
end
```

マイグレーションファイルを編集したら `rails db:migrate` でマイグレーションを実行してください。

### 4-7.Userモデルの編集

- 以下を追加

```user.rb
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]

  # 以下を追加
  def social_profile(provider)
    social_profiles.select { |sp| sp.provider == provider.to_s }.first
  end

  def set_values(omniauth)
    return if provider.to_s != omniauth["provider"].to_s || uid != omniauth["uid"]
    credentials = omniauth["credentials"]
    info = omniauth["info"]

    access_token = credentials["refresh_token"]
    access_secret = credentials["secret"]
    credentials = credentials.to_json
    name = info["name"]
    # self.set_values_by_raw_info(omniauth['extra']['raw_info'])
  end

  def set_values_by_raw_info(raw_info)
    self.raw_info = raw_info.to_json
    self.save!
  end
  # 以上を追加
end
```

### 4-8.コントローラーを編集

- classの `ApplicationController` を `Devise::OmniauthCallbacksController` に変更するのを忘れないように！


```omniauth_callbacks_controller.rb
# ApplicationController を Devise::OmniauthCallbacksController に変更
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  # 以下を追加
  def line; basic_action end

  private
  def basic_action
    @omniauth = request.env["omniauth.auth"]
    if @omniauth.present?
      @profile = User.find_or_initialize_by(provider: @omniauth["provider"], uid: @omniauth["uid"])
      if @profile.email.blank?
        email = @omniauth["info"]["email"] ? @omniauth["info"]["email"] : "#{@omniauth["uid"]}-#{@omniauth["provider"]}@example.com"
        @profile = current_user || User.create!(provider: @omniauth["provider"], uid: @omniauth["uid"], email: email, name: @omniauth["info"]["name"], password: Devise.friendly_token[0, 20])
      end
      @profile.set_values(@omniauth)
      sign_in(:user, @profile)
    end
    flash[:notice] = "ログインしました"
    redirect_to root_path
  end

  def fake_email(uid, provider)
    "#{auth.uid}-#{auth.provider}@example.com"
  end
  # 以上を追加
end

```

これで設定は完了です！
http://localhost:3000/users/sign_in にアクセスすると `Sign in with Line` が追加されていると思います。

![スクリーンショット 2020-10-24 18.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/99f3094b-6a5b-c603-df2d-1716a632e1e1.png)

ただし, 今の状態ではクリックしてもログインできません。LINE Developers側の詳細設定をしていきましょう！

## 5.LINEログイン詳細設定

### 5-1. コールバックURL

ログイン時のコールバックURLを設定していきます。

LINE Developersの任意のプロバイダーから`LINEログイン設定`を開いてください。
コールバックURLを設定するフォームがありますので, そこに入力していきます。

![スクリーンショット 2020-10-26 16.43.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/a905b8b7-a719-4faf-4eee-c4724fc174d2.png)


基本は `https://アプリ名/users/auth/line/callback` で大丈夫です！
念のため `rails routes` で URI Pattern を確認してみてください。
![スクリーンショット 2020-10-26 17.10.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/4ede5528-6417-0cb3-a63c-307cc767281a.png)

ここで注意して欲しいのが, LINEログインを使用する際のURLは `https` でないといけないということです！
http://localhost3000/users/auth/line/callback のようには設定できません。

なので開発環境で動作確認を行う際は一工夫しなければなりません。
開発環境でも動作確認を行いたい場合は次の `ngrok` を参考にしてください。
（ngrokはあくまで一例ですので, 他にも色々やり方はあります。必要のない方は読み飛ばして下さい！）

### 5-2.ngrok

`ngrok` はlocalhostに外部から接続できるようにするというサービスです。
簡単に導入できますので説明していきます。

- 以下のコマンドで `ngrok` をインストールしてください

```zsh:ターミナル
brew cask install ngrok
```
【追記（22/01/06）】
cask の利用方法が変更され, `brerw cask` コマンドは Homebrew 2.6 で非推奨になり, Homebrew 2.7 から利用できなくなっているようです。 Homebrew 2.6 まで `brew cask` としていたコマンドは、オプション `–cask` で cask を指定するように変更されています。

ですので, 上記のコマンドで `Error: Unknown command: cask` のエラーが出る場合は下記のコマンドを実行してください。

```zsh:ターミナル
brew install ngrok –cask
```

インストールが終了したらバージョン確認をしてみてください。
以下のようにバージョンが表示されればOKです！

```
❯ ngrok -v
ngrok version 2.3.35
```

ngrokのインストールが終わったら、外部アクセス用 https のURLを発行しましょう。
以下のコマンドを実行してください。

```zsh:ターミナル
ngrok http 3000
```
- 3000 はポート番号なので適宜変更してください。
- また, `ngrok` とは別にRailsサーバーも起動しておく必要があるので, 起動していない場合は `rails s` でサーバーを起動してください。)

コマンドを実行するとこのような感じで表示されると思います。

![スクリーンショット 2020-10-26 17.37.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/1d0a5033-a788-b4e7-3574-fc4540ef74a9.png)

こちらで表示された http://xxxxxxxx.ngrok.io で外部からlocalhostのWebサーバーにアクセスすることが可能になります。


今回は `https` で接続したいので下の方の https://xxxxxxxx.ngrok.io をコールバックURLに指定してください。

![スクリーンショット 2020-10-26 17.48.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/5c4e4308-3448-51f0-8d43-584e722c16fa.png)

【注】ngrokで作成したURLには使用制限があり, 発行して8時間が経過すると, 設定したURLではアクセスできなくなってしまいます。その際は再度 `ngrok http 3000` を実行し, 発行されたURLでコールバック先を指定し直してください。

→ 以前は8時間だったのですが, 現在は2時間に短縮されてしまっています。。LINEログインの動作確認だけだと2時間あれば十分かと思いますが, 他に便利なサービスがあれば追記します😓




#####【Rails6の場合】

Rails6から保護機能が強化され, ngrokで発行したホスト名ではアクセスできないので, 許可したいホスト名をRailsアプリ側に登録しなければなりません。
（Rails5を使用されている方はこちらは読み飛ばして頂いて大丈夫です。）

それではngrokで作成したホストをRailsのアプリに登録していきます。

`config/environments/development.rb` に下記を記載し、ホワイトリストに許可したいhostを追加すればOKです！
許可したいホスト名には `xxxxxxxx.ngrok.io` の部分を追加してください。（httpsなどの部分は不要です。）

```config/environments/development.rb
Rails.application.configure do
  # 以下を追加
  config.hosts << "許可したいホスト名"
end
```

ただ先ほど説明したように, ngrokは期限が切れるたびに違うURLを発行し直さなければなりません。

そうすると許可したいホスト名も毎回書きかえないといけなくなりますので, 以下の方法も紹介しておきます。

```config/environments/development.rb
Rails.application.configure do
  # 以下を追加
  config.hosts.clear
end
```

これにより, すべてのホスト名に対するリクエストを通過させることができます。
（ただしせっかくRails6で追加された保護機能を無効化してしまうため、どちらを選択するかはお任せします。）

ここまでの設定が完了したらngrokで発行したURLにアクセスできるようになります！
すでにサーバーを起動している場合は再起動し, 実際にログイン画面のURLにアクセスして確認してみてください。

![スクリーンショット 2020-10-26 23.01.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/fd0fceb4-9904-228d-b996-ee511668c066.png)



【注】ngrokとlocalhostのサーバーは同時に起動させてください。終了させる時はどちらも `Ctrl + C` で終了できます。






### 5-3.チャネルの公開

最後に, 作成したチャネルを公開していきます！

上の方に表示されている `非公開` ボタンをクリックすると「チャネルを公開しますか？」という表示が出てきますので, 公開をクリックしてください。
![スクリーンショット 2020-10-26 17.52.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/1db358c3-4f0f-aa50-de39-8d240765c3c7.png)



きちんと公開できていれば `公開済み` に切り替わります。
![スクリーンショット 2020-10-26 17.53.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/91d11604-18fd-aed7-e2f2-1128ccf19fd4.png)

ここまで設定したらLINEログインの設定は終了です！！！
ログイン画面の `Sign in with Line` をクリックするとログイン画面が表示されますので, そちらからログインできるようになります！
（初回ログインの際は, LINE登録時のメールアドレスとパスワードを求められる場合があります）

![スクリーンショット 2020-10-26 22.03.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665145/1857a083-ec8a-d328-2bc1-f806272efc41.png)

Messaging API を利用してLINEBotなどを作る場合, LINEログイン機能は大変便利だと思いますので, 少しでも導入する際の参考になれば幸いです。

仕様の変更や補足があれば随時更新していきたいと思います！
お疲れさまでした〜！✨