Rails 搭配 Omniauth line
本篇內容
- 前置作業
- 安裝相關套件
- 生成 User Model
- 設定 Line Login
- 新增身份驗證
- 實作登入登出
前置作業
1. 建立新檔案
使用 Rails 指令新增專案:
rails new demo cd demo
2. 產生空白頁
使用 Rails 指令新增 Controller:
rails g controller home
之後新增 app/views/home/index.html.erb
。
最後在 config/routes.rb
中新增以下內容:
root to: "home#index"
安裝相關套件
在 Gemfile
中加入以下內容:
gem 'devise' gem 'omniauth-line', git: 'https://github.com/etrex/omniauth-line.git' gem "dotenv-rails", "~> 2.7"
加入後執行 bundle
。
生成 User Model
請執行以下指令:
rails g devise:install rails g devise user rails g migration add_line_login
開啟剛剛新增的 db/migrate/xxxxxxxxx_add_line_login.rb
並在 change
方法中加入以下內容:
add_column :users, :line_id, :string add_column :users, :name, :string add_column :users, :image_url, :string
另外,由於我們之後要以 line_id
區分使用者,這導致 email
column 的值可能會重複(因為 Devise 預設 email 的值為 '' ),因此需要解決 email
重複的問題,以下新增一個 migration:
rails g migration resolve_users_email_unique
開啟新增的 db/migrate/xxxxxxxxx_resolve_users_email_unique.rb
更改為以下內容:
def up change_column :users, :email, :string, null: true, default: nil end def down change_column_null :users, :email, false, SecureRandom.uuid end
此段主要為修改 email
column,當 user
被建立時,預設值為 nil
,以此來避免唯一鍵重複,而 down
中的 SecureRandom.uuid
則是為了避免原本 email
為 nil
的資料 db rollback
後發生重複的問題。
到了這一步後就可以執行 Database migrate:
rails db:migrate
設定 Line Login
新增 .env
並在其中放入以下內容:
LINE_LOGIN_CHANNEL_ID= 你的 CHANNEL ID
LINE_LOGIN_CHANNEL_SECRET= 你的 CHANNEL SECRET
該資訊可以在 Line Developers 找到,點擊 LINE LOGIN 的 CHANNEL,可以看到以下畫面:
LINE LOGIN CHANNEL ID,複製該內容貼至
.env
LINE LOGIN CHANNEL SECRET,複製該內容貼至
.env
(與 LINE LOGIN CHANNEL ID 同頁面的下方)
在 Callback URL 部分填入
https://{your-domain-name}/users/auth/line/callback
在 config/initializers/devise.rb
的 Devise.setup
區塊中新增以下內容:
config.omniauth :line, ENV['LINE_LOGIN_CHANNEL_ID'], ENV['LINE_LOGIN_CHANNEL_SECRET']
在 app/models/user.rb
開啟 Omniauthable 功能
devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :validatable + :recoverable, :rememberable, :validatable, + :omniauthable, omniauth_providers: [:line]
在 app/models/user.rb
新增 from_omniauth
方法
def self.from_omniauth(auth) if auth.provider == "line" user = User.find_or_create_by(line_id: auth.uid) user.update(name: auth.info.name, image_url: auth.info.image) user end end
因為 LINE Login 只會傳入 line_id
而沒有 email
和 password
,因此 email
和 password
為非必填,在 app/models/user.rb
中加入以下內容:
def email_required? false end def password_required? false end
新增 omniauth controller
rails g controller OmniauthCallbacks
並在其中填入以下內容:
def line user = User.from_omniauth(request.env["omniauth.auth"] ) sign_in user redirect_to root_path end
在 config/routes.rb
中加入以下內容:
- devise_for :users + devise_for :users, controllers: { + omniauth_callbacks: 'omniauth_callbacks' + }
新增身份驗證
在 app/controllers/application_controller.rb
中加入以下內容:
include Rails.application.routes.url_helpers def authenticate_user return if current_user.present? redirect_to user_line_omniauth_authorize_path end
之後只需要在先登入才能進行動作的 Controller 中加入以下內容:
before_action :authenticate_user
Devise 預設是
before_action :authenticate_user!
實作登入登出
完成至上一步已經可以進行 Line Login,但假如希望登入登出這件事並非強制的話,可以增加登入登出的列表。
在 app/views/layouts/application.html.erb
的 <body> ... </body>
之中加入以下內容:
<nav> <h1> <% if current_user.present? %> <%= current_user.name %> 您好: <%= link_to "登出", destroy_user_session_path, method: :delete %> <% else %> <%= link_to "登入", user_line_omniauth_authorize_path %> <% end %> <h1> <hr /> </nav>
這樣子就可以在未登入時可以登入:
已登入時可以登出: