プログラミング

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


Webサービスを実装するに当たり、ログイン・認証機能は殆どの場合必須になります。

この記事では、Ruby on Rails 6 + Devise + AWS SESを用いて簡単にログイン認証を実装する手順を解説します。

大まかな手順は以下のようになります。

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

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

まずRailsプロジェクトを作成します。

rails new rails-devise-ses-auth --skip-test --skip-turbolinks

 

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

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

 

一旦サーバーを立ち上げて動作確認をします。

bundle exec rails s

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

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

git add -A
git commit -m "first commit"

commitが作成されたらgithubにプッシュします。

git push origin master

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

Deviseは、Railsで認証周りを扱うgemです。

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

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

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

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

Gemfileにdeviseを追加

Gemfileに以下を追記します。

gem "devise"

追記したら

bundle install

でdeviseが使用できるようになります。

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

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

rails g devise:install

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

前項でdevise:installするときに以下のようにコンソールに表示されます。

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

Some setup you must do manually if you haven't yet:

  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.

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

root to: "home#index"

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

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

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

rails g devise:views

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

それぞれ対応していきましょう。

1.default_url_optionsの設定

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


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

2.トップ画面の作成

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

rails g controller home index

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

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

root to: "home#index"

 

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

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

<body>
<div class="container">
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>
  <%= yield %>
</div>
</body>

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

 

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

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

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

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

rails g devise User

デフォルトで作成されたUserモデルは以下のようになります。

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
end

devise_create_users.rb(migrationファイル)

# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  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

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

devise_create_users.rb(migration)

# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  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モデルのマイグレーション

前節でmigrationファイルを作成したので、これをもとにUserモデルのテーブルを作成します。

bundle exec rails db:migrate

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

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

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

rails g devise:views users

これでビュー周りのボイラープレートが作成できました。

参考:DeviseまわりのControllerを自動生成するには?

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のダッシュボードの「ドメインの登録」からドメインの新規取得が行えます。

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

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

その他の選択肢としては、1円からドメインを取得できるお名前.comなどが有力ですね。

ドメインの検証

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から、検証済のメールアドレスに対してメールのテスト送信を実行することができます。

AWS SESとRailsとのつなぎこみ

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はバージョン管理に含めないように注意してください。

参考記事

事故防止のため、require_master_keyオプションをtrueにする

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

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

config.require_master_key = true

AWS SES SDKをGemfileに追加

Gemfileを追記します。

gem "aws-ses"

initializersでawsの設定を記述

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

ActionMailer::Base.add_delivery_method :ses,
                                       AWS::SES::Base,
                                       access_key_id: Rails.application.credentials.aws[:access_key_id],
                                       secret_access_key: Rails.application.credentials.aws[:secret_access_key],
                                       server: 'email.us-west-2.amazonaws.com' #オレゴン

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

development.rbのaction_mailer.delivery_methodを書き換えます。

  config.action_mailer.delivery_method = :ses

参考:その他に使えるメール送信SaaSは?

AWS SESの他には、SendGrid や Mailgun などを使うこともできます。

動作確認

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

  • 新規ユーザーが作成できるか
  • welcomeメールが飛ぶか
  • パスワードを変更したりリセットできるか

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

スタイルシートを調整していい感じにする

このままだと味気ないので、CSSを調整していい感じにします。

今回はピュアCSSフレームワーク(jsが含まれておらず、CSSのみで完結しているもの)bulmaを使います。

Rails 6系ではデフォルトでwebpackerが利用できるようになっているので、yarn addでライブラリをインストールできます。

yarn add bulma

application.jsに以下を追記することでCSSをインポートすることができます。

import "bulma/css/bulma.css"

あとはbulmaのドキュメントを見ながら、適当にCSS Classを付与していきます。

bulmaのレールに従っていけば、自分でCSSファイルをイチから書かなくてもそれなりにいい感じのデザインができます。

 

...と、ここで初稿は心が折れたので、スタイルシートを書く画面に当てるのはこれからやるとして一旦リポジトリ公開することにします。

まとめ

いかかでしたか?

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

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

参考書籍

 


-プログラミング
-

© 2020 Permanent Til Powered by AFFINGER5