🔑

Rails 6+Devise+AWS SESで簡単なログイン認証を実装する手順

2021/04/26に公開

TL:DR

Webサービスを実装にするにあたり、必須機能になる認証機能をRails 6 + devise + AWS SESを用いて作成する

前提バージョン

  • ruby 3.0.1
  • rails 6.1.3.1
  • devise 4.7.3
  • aws-sdk-rails 3.6.0

手順概要

  • Railsプロジェクトの新規作成
  • 認証ライブラリDeviseのインストール
  • 認証用のModelであるUserクラスを作成
  • AWS SESの設定
  • RailsとAWS SESとのつなぎこみ
  • メール文言の編集
  • Web UIの編集
  • 動作確認

Railsプロジェクトの新規作成

Railsプロジェクトを作成します。まずはこんな感じ

rails new rails-devise-ses-auth --skip-system-test --skip-turbolinks -S -C

github上ににpushできるように、git remoteでoriginを追加

git remote add origin git@github.com:yohira0616/rails-devise-ses-auth.git

Rails newするときのオプションの詳細についてはこちら

https://zenn.dev/yukito0616/articles/7cd2dde18c90d4

いったんサーバーを立ち上げ動作確認。

bundle exec rails s

localhost:3000にアクセスして、railsのデフォルト画面が表示されればOKです

動作確認をしたらfirst commitをした後にgithubにpushします。

git add -A
git commit -m "first commit"
git push origin master

認証ライブラリDeviseのインストール

Deviseは、Railsで認証周りを扱うgemで最もよく使われているライブラリです。

https://github.com/heartcombo/devise

devise標準でできることは大まかに以下のとおりです。

  • ユーザーの登録・退会・ユーザー情報の更新
  • ログイン・ログアウト
  • ログインパスワードの変更・再発行

他、モジュールを追加することで以下のことができるようになります。

  • メールアドレスの存在確認
  • アカウントロック
  • タイムアウトの設定
  • ユーザーのログイン履歴を記録
  • Twitter,FacebookなどからのOAuth認証

Gemfileにdeviseを追加

bundle add devise

rails gでdevise関連のファイルを自動作成

deviseには専用のジェネレータが用意されていて、これを使用することで簡単にdevise用の設定ファイルを作成することができます。

bundle exec rails g devise:install

手動でセットアップしないといけない箇所を設定する

先ほどのコマンドでコンソールに以下のようなメッセージが出ると思います。

===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"
     
     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views
       
     * Not required *

===============================================================================

これらについて設定してきます。

1.default_url_optionsに以下を追記

メッセージに書いてあるとおりに、development.rbに以下を追記します

development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

2.トップ画面の作成

Railsデフォルトではないトップ画面を一枚作成します。

bundle exec rails g controller home index

これでindexメソッドと持ったHomeControllerと、views/home/index.html.erb が自動生成されます。

routes.rbのブロックの末尾でroot toを設定してデフォルトのホーム画面を追加します。

routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end

3.エラーメッセージを表示できるようにapplication.html.erbの修正

application.html.erbのbody部分を修正します。

application.html.erb
  <body>
  <div class="container">
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
  </div>
    <%= yield %>
  </body>

4.については次の節で対応します。

参考:ほかの認証の選択肢

認証系のライブラリとしては他にはsorceryなどがあります。

sorcery

https://github.com/Sorcery/sorcery

認証を完全に外出ししてSaaSを利用するならば、FirebaseやAuth0などが有力です。

firebase authentication

https://firebase.google.com/docs/auth?hl=ja

auth0

https://auth0.com/docs/quickstart/backend/rails

認証用のModelであるUserクラスを作成

具体的に、認証に利用するModelクラスを作成します。

ここではUserクラスを認証用のモデルとして作成します。

deviseのジェネレータに認証用のモデルを作成するコマンドがあるのでそれを利用します。

bundle exec rails g devise User

Userモデルとマイグレーションファイルが作成されますが、confirmable(メールアドレスの存在確認ができるかどうか)は有効にしたいので、以下のように修正します。

user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable
end

migration

1234567890devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      ## Database authenticatable
      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

Userモデルのマイグレーションを行うため、db:migrateを行ってUsersテーブルを作りましょう

ユーザーの新規登録画面の作成

Deviseでは、実はviewやcontrollerを自分で作成しなくても(deviseのレールに乗るという前提で)認証画面一式を用意してくれます。

とはいえ、このままだとカスタマイズできないので、deviseのscaffoldを使ってボイラープレートを作成し、修正を加えていきます。

bundle exec rails g devise:controllers users

でControllerのボイラープレートを作成することができます。

AWS SESの設定

Amazon Web Service Simple Email Service(AWS SES)はメール送信を扱うAWSのフルマネージドサービスです。

フルマネージドサービスを利用することによって、自前でメールサーバーを立てなくてもメール送信処理が実装できるようになります。

AWS SESを利用するために必要な条件は以下の通りです。

  • メール送信元として使用するための検証済のドメインが必要
  • サンドボックス環境(本番用の審査を受けていない状態。)では、送信先も検証済のメールアドレスである必要がある

AWS Route 53を利用してドメインを取得

メール送信元として使用するためのドメインはRoute 53を利用して取得すると楽です(有料)

AWS Route53のダッシュボードの「ドメインの登録」欄の右下の「ドメイン」欄からドメインの登録が行えます。

ハマりポイントとして、住所に日本語が含まれているとドメインの取得に失敗します...ので英語で記述する必要があります。

画面上での購入手続きが完了とするとメールアドレスに確認用メールが届くので、記載されたリンクをクリックすると正式にドメインが取得できます。

ドメインの検証

AWS SESの画面に戻ります。

Domains -> Verify a New Domainをクリックし、先程取得したドメインを入力。

「Generate DKIM Settings」にチェックを入れて「Verify This Domain」から手続きを進めます。

Route 53を利用していると、ネームサーバーの設定を自動でやってくれるので楽です。

メールアドレスの検証

AWS SESでは、本番環境の申請を通していないと、予め設定されたメールアドレスにしかメールを送信することはできません。(メール送信スパムの防止のためかと思われる)

検証済メールアドレスの追加は、Email Addresses -> Verify a New Email Addressから新規に追加することができます。

追加するとそのメールアドレスに対して確認メールが送信されるので、確認メールのリンクをクリックするとVerify済のメールアドレスとして認識されます。

なので自分のメールアドレスを検証済メールアドレスとして登録しておきます。

テスト送信

Domains -> Send a Test Emailから、検証済のメールアドレスに対してメールのテスト送信を実行することができます。

RailsとAWS SESとのつなぎこみ

credentialの仕組みを使ってAWSのアクセストークンを秘匿しながら記述

AWSのAPIを利用するためには、access_key_idとsecret_access_keyを指定してあげる必要があります。

これらは秘匿情報であるので、Railsのcredential機能を使って

EDITOR="vi" bin/rails credentials:edit

このコマンドを実行すると、vimでcredentialの編集画面が開くので、自身のAWSキー情報を入力したら保存して終了します。

作成されるcredentials.yml.encはバージョン管理に含めても良いですが、master.keyはバージョン管理に含めないように注意してください。

参考:
https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39

require_master_keyオプションをtrueにする

require_master_keyをtrueにすると、master.keyがない環境ではRails起動時にエラーになるようになります。

development.rbのブロックの末尾に以下を追記します

development.rb
config.require_master_key = true

RailsでAWS SESの設定をする

RailsでSESの設定をするには、gemはaws-sesではなくaws-sdk-railsを使う方が簡単です。

bundle add aws-sdk-rails

initializersでawsの設定を記述
config/initializers/aws.rbを作成し、以下の記述を追加します。

aws.rb
Aws::Rails.add_action_mailer_delivery_method(
  :ses,
  credentials: Aws::Credentials.new(Rails.application.credentials.aws[:access_key_id],
                       Rails.application.credentials.aws[:secret_access_key]),
  region: 'us-west-2'
) # オレゴン

development.rbのaction_mailer.delivery_methodを書き換えます。yourdomain.comと書いてあるところは自分の取得したドメインを記述します。

development.rb
config.action_mailer.delivery_method = :ses

app/mailers/application_mailer.rb

application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'noreply@yourdomain.com'
  layout 'mailer'
end

config/initializers/devise.rbを書き換えます。

devise.rb
config.mailer_sender = 'MyService <noreply@yourdomain.com>'

これで、ActionMailerでSESを利用する設定の定義ができました。

参考:メール送信SaaSの別の選択肢

メール送信SaaSとしては、AWS SESの他には、SendGridやMailgunなどを使うこともできます。

https://sendgrid.kke.co.jp/

https://www.mailgun.com/

メール文言の編集

deviseは、特に設定をしなくても組み込みのテンプレートでメールを送信してくれますが、実際問題としてメール文言が編集できないと不便です。

devise.rb
# 247行目くらい
config.scoped_views = true
bundle exec rails g devise:views users

でメールのテンプレートを出力することができます。

例えば、メールアドレス認証の文言を以下のようにすると

confirmation_instructions.html.erb
<p>Welcome <%= @email %>!</p>

<p>Hello!下のリンクから登録を完了してください</p>

<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>

(gmailのスクリーンショット)

こんな感じでメールが届きます。

Web UIの編集

CSSを当てていきます。本記事ではいったんJavaScriptを利用せずに構成するので、cssを取り出せるようにwebpackerの設定を変更します。

webpacker.yml
  extract_css: true

app/javascript/application.scssを作成し、application.html.erbの

<%= stylesheet_link_tag 'application', media: 'all' %>

<%= stylesheet_pack_tag 'application', media: 'all' %>

に変更します。これでrailsから、webpackerでトランスパイルされたcssを読み込めるようになります。

※ webpackerを利用する場合、app/assets/stylesheets/ は削除してOKです

reset.cssの適用

とりあえずreset.cssを適用します。reset.cssは数種類あって迷うのですが今回はmodern-css-resetを使用します。

https://github.com/andy-piccalilli/modern-css-reset

参考:
https://coliss.com/articles/build-websites/operation/css/css-reset-for-modern-browser.html

yarn add modern-css-reset

したあとに、application.scssから参照するには以下のように書きます。

application.scss
@import '~modern-css-reset/dist/reset.min';

node_modules下のライブラリの中のパスを通すには先頭に ~をつけたパスを記述します。

CSSフレームワークの使用

CSS書くのめんどくさいのでCSSフレームワークを導入します。

参考:
https://mid-works.com/columns/freelance-career/engineers/1114801

これもまたいろいろなCSSフレームワークが乱立していますが、今回はJavaScriptを使わないpure cssを使いたいので、Bulmaを採用します。

https://bulma.io/

yarn add bulma

した後、application.scssに @import '~bulma/css/bulma.min'; を追記します。

UIを調整

手順をいちいち書いていくと長くなってしまうのでここの /viewsを参照してください(一部割と適当)

https://github.com/yohira0616/rails-devise-ses-auth

動作確認

この時点で、認証周りの基本的なバックロジックは完成しているので、rails sでサーバーを立ち上げて

localhost:3000/users/sign_up からアカウント登録をすることができます。

  • 新規ユーザーが作成できるか
  • メールアドレスの確認メールが飛ぶか
  • パスワードを変更したりリセットできるか
  • 退会できるか

などをブラウザ上から動作確認することができます。

一連の機能はdeviseが用意してくれている(localhost:3000/rails/info/routes を見ると、deviseが設定してくれているパスがわかります)ので実際に手を動かしてみてください。

まとめ

今回は、Ruby on Rails + DeviseでWebサービスには欠かせない認証を最小限の構成で構築しました。

さらにAWS SESを使用することによってメールサーバーを構築しなくてもメールが送れることを確認できました。

自分の既存記事のリライトのつもりでやったらawsライブラリ周りの仕様が変わっていて思ったより時間がかかったのは内緒。

Discussion