Railsでマジックリンクの機能を実装

Kota Miyake
Ruffnote
Published in
8 min readMar 20, 2019
Photo by CMDR Shane on Unsplash

多くのサービスでは、メールアドレスとパスワードを入力してログインするという方法を採用しています。

この方法はシンプルでわかりやすいので、広く普及してきました。ただ問題になったのはパスワードを考える・管理するという方法です。

現在は色々なログイン情報を管理するためのツールがあります。ですが、それらのツールを皆が使っているかと言うとそうでもありません。

ユーザーの中には自分が覚えやすい簡単なパスワードにしたり、他のサービスで使っているパスワードを流用したりしていたりします。

そこで登場したのが、マジックリンクによるログインシステムです。

パスワード認証やマジックリンクについての説明は以下の記事に譲るとして、マジックリンクというのは要は1回限りの認証用のリンクを使ってログインする方法です。

パスワード認証ってもう古くないですか? | 東京上野のWeb制作会社LIG

前置きはこのくらいにして、さっそく Rails アプリで実装してみたいと思います。

今回は passwordless という gem を利用します。

まずは Rails アプリを作成し、 Gemfile に passwordless を追加して bundle install するところまで。

$ rails new magicklink
$ cd magicklink
$ vim Gemfile # gem 'passwordless' を追加
$ bundle install

gem のインストールが完了したら、今度は passwordless のマイグレーションファイルを生成するコマンドを実行し、マイグレーションします。(database.yml の設定は適宜お願いします。)

$ ./bin/rails passwordless:install:migrations
$ ./bin/rails db:create db:migrate

それからログインユーザーとして User モデルを用意します。

$ ./bin/rails generate model User email
$ ./bin/rails db:migrate

それでは passwordless の設定を追加して試してみたいと思います。

user.rb に passwordless_with :email を追加します。

# user.rb
class User < ApplicationRecord
passwordless_with :email # 追加
end

routes.rb には passwordless_for :users を追加します。

# routes.rb
Rails.application.routes.draw do
passwordless_for :users
end

そして /users/sign_in にアクセスするとマジックリンクを送るためのメールアドレス入力欄が表示されます。

Send magick link

では console からユーザーを登録して、マジックリンクを送ってみましょう。

irb(main):001:0> User.create(email: "miyake@ruffnote.com")
(1.8ms) SET NAMES utf8, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
(1.2ms) BEGIN
User Create (1.9ms) INSERT INTO `users` (`email`, `created_at`, `updated_at`) VALUES ('miyake@ruffnote.com', '2019-03-15 01:41:36', '2019-03-15 01:41:36')
(4.5ms) COMMIT
=> #<User id: 1, email: "miyake@ruffnote.com", created_at: "2019-03-15 01:41:36", updated_at: "2019-03-15 01:41:36">

上記のマジックリンク送信画面に登録したメールアドレスを入力して Send magick link をクリックすると以下のようにマジックリンクが記載されたメールが送信されます。

事前に default_url_options の設定を忘れずに。

Sent mail to miyake@ruffnote.com (56.6ms)
Date: Fri, 15 Mar 2019 10:44:27 +0900
From: CHANGE_ME@example.com
To: miyake@ruffnote.com
Message-ID: <5c8b037b1b94b_9d383ff66b5cd1bc9826@kotamiyake-pro.local.mail>
Subject: =?UTF-8?Q?Your_magic_link_=E2=9C=A8'?=
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Here's your link: http://localhost:3001/users/sign_in/FwnvkH89BT2Tuh-NGPz7cyCH5ZW3tK3b4UL-snIGD-c

こちらのリンクを URL アドレスバーに入力すると正常に処理されれば root へリダイレクトします。( root 用の controller と view は home など適宜用意してください)

実際にログインできているか current_user メソッドを追加して確認してみたいと思います。

# application_controller.rb
class ApplicationController < ActionController::Base
include Passwordless::ControllerHelpers
helper_method :current_userdef current_user
@current_user ||= authenticate_by_cookie(User)
end
end
# home/index.html.erb
<% if current_user.present? %>
<%= current_user.email %>
<%= link_to 'ログアウト', '/users/sign_out', method: :delete %>
<% else %>
ログインしていません。
<% end %>

これでメールアドレスが表示されればログイン成功です。

ログイン後

ログアウトも機能しているか確認します。

ログアウト後

あとは current_user を使って参照権限などを設定いけば良いかと思います。

ここまで passwordless を使った簡単なマジックリンクを使った認証機能の実装を紹介しました。

パスワードを使わないログインで安全では…と思いきや、結局メールを利用しているので、メールアカウントの認証情報を破られれば筒抜けです。

またメールを受信して、リンクをクリックするというステップは使う側からすると、ちょっと面倒な気もします。

とは言え、複数のサービスで同じパスワードを流用するような問題は解決することはできます。

が、それもメールアカウントの管理が適当になってしまうと意味がありません。

最終的には使う側が上手に、そして簡単に管理できるようなメールアドレスとパスワードに変わる認証方法が生まれるのを待つ必要がありそうです。

皆さんもパスワード管理には最新の注意を払いましょう。

--

--