RailsにAuth0の認証機能を追加、ついでにRenderでデプロイしてみた
はじめに
久しぶりにRailsで開発をすることとなり、認証機能にAuth0を使用してみました。
今まではdeviseを使って認証機能を作成していたのですが、Auth0でも「サクッと」できるという噂を聞き、それならばRenderを使ってデプロイまで「サクッと」やってみよう〜ƪ(˘⌣˘)ʃ
そして、案の定つまづきまくったので、備忘録としてまとめました😅
Auth0、Renderとはなんぞや?簡単に説明!!
Auth0とは?
認証・認可プラットフォームの一つです。
Auth0を利用すると、自分で開発したアプリ側では特に特別なコーディングをすることなく、スライドボタンをオンにするだけでfacebookやGoogle、Xなど30種類以上のソーシャルアカウントで簡単サインインができます。複雑なOAuthの実装やトークンの管理などに煩わされることなく、機能の開発に専念することができます。
Renderとは?
Webアプリケーションやバックエンドサービスのデプロイとホスティングを簡素化するクラウドプラットフォームです。
様々なプログラミング言語やフレームワークをサポートしていて、Githubリポジトリを直接連携することで、コードの変更を自動的にデプロイでき、独自のドメインの設定なども可能です。
ダッシュボードから環境変数の管理やログ・メトリクスの確認などもできるため、デプロイに関するプロセスを大幅に簡素化することができます。
開発の手順
Rails側の環境構築をする
Railsアプリケーションを新規作成する
- rails_auth_appという名前でフォルダーを作成し、Railsをインストールします。
# Homebewを最新化する
$ brew update
# 利用可能なRubyのバージョンを確認する
$ rbenv install -l
# 指定のバージョンのRubyをインストールする
$ rbenv install 3.0.2
# デフォルトのRubyを設定する
$ rbenv global 3.0.2
# Bundlerをインストールする
$ gem install bundler
3 Railsをインストールする
$ gem install rails
-
home
ディレクトリを作成してindex.html.erb
ファイルを作成しておきましょう。
中身はからで大丈夫です!! - ルーティングを記述します
Rails.application.routes.draw do
root 'home#index'
end
これでいったん、Railsアプリケーション側の作成は終わりです。
Auth0を設定する
Auth0アカウントを作成する
アカウントがない場合は、Auth0のアカウントを作成します。
Auth0アプリケーションにRaislアプリケーションを作成する
- 左側のメニューバーからApplicationsを選択し、
+ Create Application
のボタンをクリックします。 - アプリケーションの名前を決めて(わかりやすいようにRailsのアプリ名と同じrails_auth_appとしておきます)
Regular Web Applications
を選択して Crearteボタンをクリックします。 - 使用するプロジェクトにRuby on Railsを選択します。
Auth0にRailsのアプリケーションが作成されました。
RailsアプリケーションにAuth0認証を連携する
Quickstartのタブで「I want to integrate with my app」の手順に従い、RailsアプリケーションとAuth0を連携させていきます。
Configure Callback URLs、Configure Logout URLsのURLを設定する
Settingsの
Allowed Callback URLsにhttp://localhost:3000/auth/auth0/callback
Allowed Logout URLsにhttp://localhost:3000
と設定します。
Save Changesをクリックして設定を保存しましょう。
Install the Auth0 SDK
必要なGemをインストールしてアプリケーションに追加していきます。
Gemfileにomniauth-auth0
とomniauth-rails_csrf_protection
を追加してbundle install
しましょう。
gem 'omniauth-auth0', '~> 3.0'
gem 'omniauth-rails_csrf_protection', '~> 1.0' # prevents forged authentication requests
Initialize Auth0 Configuration
Auth0を設定するためのファイルを作成します。
- config/auth0.ymlを作成する
Auth0のドメイン、クライアントID、クライアントシークレットなどの情報を設定するファイルで、異なる環境(開発、テスト、本番)ごとに設定を分けることができます。
$ touch config/auth0.yml
コマンドでconfigディレクトリにauth0.ymlという設定ファイルを作成します。
SettingsのBasic informationに記載してある
Domain
Client ID
Client Secret
の値をファイルに記述します。
development:
auth0_domain: YOUR_DOMAIN
auth0_client_id: YOUR_CLIENT_ID
auth0_client_secret: <YOUR AUTH0 CLIENT SECRET>
- config/initializers/auth0.rbを作成します
$ touch config/initializers/auth0.rb
コマンドでconfig/initializersディレクトリにauth0.rbという設定ファイルを作成します。
このファイルはRailsの初期化プロセス中に読み込まれ、Auth0の設定を初期化し、アプリケーションで使用できるようにします。
config/auth0.ymlからAuth0の設定値を読み込んだり、Auth0のミドルウェアをRailsアプリケーションに組み込みます。
JWTの検証オプションを設定やセッション管理の設定を行なっているのもこちらのファイルです。
AUTH0_CONFIG = Rails.application.config_for(:auth0)
Rails.application.config.middleware.use OmniAuth::Builder do
provider(
:auth0,
AUTH0_CONFIG['auth0_client_id'],
AUTH0_CONFIG['auth0_client_secret'],
AUTH0_CONFIG['auth0_domain'],
callback_path: '/auth/auth0/callback',
authorize_params: {
scope: 'openid profile'
}
)
end
セキュアモジュールを作成する
deviseでいうauthenticate_user!メソッドのようなログイン必須機能を実装します。
app/controllers/concernsディレクトリにsecured.rbを作成します。
$ touch app/controllers/concerns/secured.rb
module Secured
extend ActiveSupport::Concern
included do
before_action :logged_in_using_omniauth?
end
def logged_in_using_omniauth?
redirect_to '/' unless session[:userinfo].present?
end
end
コントローラを作成する
Auth0用のコントローラを作成します。
$ rails generate controller auth0 callback failure logout
class Auth0Controller < ApplicationController
def callback
auth_info = request.env['omniauth.auth']
session[:userinfo] = auth_info['extra']['raw_info']
redirect_to '/dashboard'
end
def failure
@error_msg = request.params['message']
end
def logout
reset_session
redirect_to logout_url, allow_other_host: true
end
private
AUTH0_CONFIG = Rails.application.config_for(:auth0)
def logout_url
request_params = {
returnTo: root_url,
client_id: AUTH0_CONFIG['auth0_client_id']
}
URI::HTTPS.build(host: AUTH0_CONFIG['auth0_domain'], path: '/v2/logout', query: to_query(request_params)).to_s
end
def to_query(hash)
hash.map { |k, v| "#{k}=#{CGI.escape(v)}" unless v.nil? }.reject(&:nil?).join('&')
end
end
- ダッシュボード用のコントローラを作成します
class DashboardController < ApplicationController
include Secured
def show
# session[:userinfo] was saved earlier on Auth0Controller#callback
@user = session[:userinfo]
end
end
ルーティングを作成する
Rails.application.routes.draw do
get 'dashboard', to: 'dashboard#show'
get '/auth/auth0/callback' => 'auth0#callback'
get '/auth/failure' => 'auth0#failure'
get '/auth/logout' => 'auth0#logout'
end
ビューを作成する
- ログイン・ログアウトボタンを実装します。
<h1>Home index</h1>
<p>Find me in app/views/home/index.html.erb</p>
<%= button_to 'Login', 'auth/auth0', method: :post %>
<%= button_to 'Logout', 'auth/logout', method: :get %>
- views/dashboard/show.html.erbファイルの中身を作成します
<h1>Dashboard show</h1>
<p>Find me in app/views/dashboard/show.html.erb</p>
<div>
<p>Normalized User Profile:<%= JSON.pretty_generate(@user[:info])%></p>
<p>Full User Profile:<%= JSON.pretty_generate(@user[:extra][:raw_info])%></p>
</div>
ローカル環境で動作確認をする
ここまで設定できたら、いよいよrails s
です❗️❗️
起動確認したら、ブラウザにlocalhost:3000のURLを入れてHome画面が表示されることを確認します。
Loginボタンをクリックすると、Auth0のログイン画面が表示され、ログイン後はDashboard#showに画面遷移し、ユーザー名が表示されるようになります👏
ここまではなんとか順調順調🎶
デプロイのためのDBを準備する
ローカルの開発環境ではデフォルトのSQLite3というDBを使用していましたが、デプロイするためにはDBを切り替える必要があります。
テストと開発環境はSQlite3のまま、本番環境だけPostgreSQLに変更していきます。
PostgreSQLをインストールする
- ターミナルにてpostgresqlの最新の安定版をダウンロードします。
$ brew install postgresql
- データベースを初期化します。
$ initdb /usr/local/var/postgres -E utf8
- PostgreSQLを立ち上げます
$ brew services start postgresql
- PostgreSQLを立ち上げた状態でユーザー設定をします。
$ createuser -s -P <ユーザー名>
Enter password for new role: <パスワードを設定>
Enter it again: <再度パスワードを入力>
RailsアプリにPostgreSQLを導入する
- Gemfileを編集します。
# Use sqlite3 as the database for Active Record
- gem "sqlite3", "~> 1.4"
group :development, :test do
# Use sqlite3 as the database for Active Record
gem "sqlite3"
end
# 本番環境にPostgreSQLを使用する
group :production do
# Use PstgreSQL as the database for Active Record
gem 'pg'
end
$ bundle install
環境設定をする
ひとまず、PstgreSQLを使用するための環境を設定していきます。
- database.ymlを編集して下記のように変更します。
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
test:
<<: *default
database: db/test.sqlite
production:
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
database: <任意のデータベース名>
username: <任意のユーザー名>
password: <%= ENV['DB_PASSWORD'] %> # .envで設定
- .envファイルを作成して環境変数を設定します。
database.ymlファイルはGitHubにアップされるため、本番環境で使用するデータベースのアクセスパスワードなどは.envというファイルを作成し、そこに記入します。
ymlファイルの最終行にあるRuby式<%= ENV['DB_PASSWORD'] %>は、.envファイルから値を引っ張ってくる指示をしています。
本番環境用にdotenv-railsというGemをインストールします。
group :production do
gem 'dotenv-rails'
end
$ bundle install
- プロジェクトフォルダ直下に.env.productionファイルを作成し、パスワードを記入します。
# 任意のパスワードは最初は記載しなくてOK
DB_PASSWORD = '<任意のパスワード>'
- .env.productionをGitHubにアップしないようにセッティングする
プロジェクトフォルダ直下に.gitignoreファイルを作成します。
※このファイルに記載されたファイルは、gitにcommitされません。
.env.production
データベースを作成する
$ bundle exec rails db:create
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite'
ターミナルメッセージでは作成されるデータベースがsqlite3となっていますが、現在いる環境が開発環境だからなのでOK👌
Renderの設定をする
GitHubと連携してデプロイするための準備をしていきます。
Renderアカウントを作成する
アカウントがない場合は、Renderのアカウントを作成します。
RenderでWebアプリを作成する
-
New
をクリック後、Web Service
を選択してアプリケーションを作成します。 - RenderとGitHubを連携させていきます
Build and deploy from a Git repository
を選択してNext
をクリックします。
連携させるリポジトリを選択してConnect
をクリックします。 - フォームに必要な情報を記入しましょう
Name
サイト名
Root Directory
空欄でもOK
Environment
Ruby
Region
Singapore (Southeast Asia)
Branch
main
Build Command
初期値
Start Command
初期値
Plans
Free
Advanced
空欄でOK
Create Web Service
ボタンをクリックします。
これでRenderにアプリケーションが作成されました。
PostgreSQLを作成する
-
New
をクリック後、PostgreSQL
を選択してデータベースを作成します。 - フォームに必要な情報を記入しましょう。
Name
任意のデータベースの名前
Database
任意のデータベースの名前
User
ユーザー名
Region
Singapore (Southeast Asia)
PostgreSQL Version
初期値
Datadog API Key
空欄でOK
Plans
Free
Create Database
をクリックします。
PosgreSQLでデータベースが作成されます。
環境設定ファイルを準備する
- puma.rbを編集します
# 初期値は2をRenderの公式ドキュメントに記載してある4に変更する
workers ENV.fetch("WEB_CONCURRENCY") { 4 }
preload_app!
- production.rbを編集します。
- config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
+ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? || ENV['RENDER'].present?
- render-build.shを記載します。
本番環境で走らせるコマンドをrender-build.shファイルに書きます。
bun/render-build.shを作成し、Renderの公式ドキュメントに従ってコマンドを記載します。
#!/usr/bin/env bash
# exit on error
set -o errexit
bundle install
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate
- render-build.shが実行されるように設定します。
本番環境が立ち上がるタイミングでrender-build.shが実行されるように、RenderのSettingsのBuild Commandを変更します。
- $ bundle install; bundle exec rake assets:precompile; bundle exec rake assets:clean;
+ $ ./bin/render-build.sh
-
render.yaml
ファイルを作成して本番環境用の設定を書いていきます。
プロジェクトフォルダ直下にrender.yamlファイルを作成しましょう。
databases:
- name: <設定したデータベース名>
databaseName: <設定したデータベース名>
user: <設定したユーザー名>
region: singapore
services:
- type: web
name: <設定したデータベース名>
env: ruby
region: singapore
buildCommand: "./bin/render-build.sh"
startCommand: "bundle exec puma -C config/puma.rb"
envVars:
- key: <%= ENV['DATABASE_URL'] %>
fromDatabase:
name: render_app
property: connectionString
- key: <%= ENV['RAILS_MASTER_KEY'] %>
sync: false
- Renderの
StartCommand
部分を書き換えます。
render.yaml
ファイルに記載のあるstartCommand: "bundle exec puma -C config/puma.rb"
をRenderのSettingsStart Command
を参考に変更しましょう。
- $ bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}
+ $ bundle exec puma -C config/puma.rb
環境変数を設定する
Render側の設定
EnvironmentからAdd Environment Variable
をクリックして、render.yaml
で設定したkey
とValue
の値を設定します。
-
DATABASE_URL
(Key)
データベースのConnections
に記載してある値Internal Database URL(Value) -
RAILS_MASTER_KEY
(Key)
config
のmaster.key
に記載されている値(Value)
Save Changes
ボタンをクリックしてせて意を変更しましょう。
Rails側の設定
RenderのConnections
の値をいれます。
DB_PASSWORD = 'Passwordの値'
DATABASE_URL = 'Internal Database URLの値'
RAILS_MASTER_KEY = 'master.keyの値'
変更したファイルをGitHubにpushしたら、デプロイする準備が始まります!!
デプロイ後の動作確認
アプリケーションのURLはRenderのダッシュボードでアプリのタイトル下に表示されています。
URLをクリックすると開発環境の時と同様の画面が表示されるはずです。
一旦設定ができてしまえば、ファイルを変更してプッシュするたびに本番環境が自動で更新してくれます🎶
認証機能サービスによる特徴
認証機能としてのDeviseはRailsアプリケーションに適した豊富な機能を提供してくれ、導入が非常に簡単であるという利点があります。オープンソースで無料で利用できるため、コストの面でも優れています。ただし、メンテナンスやスケーリングは開発者側で行う必要があります。
一方、Auth0は認証に特化したサービスとして、多くの機能やカスタマイズ性を提供してくれます。また、Auth0側でメンテナンスやスケーリングを行うため、開発者の負担が少なく、高いセキュリティを確保できます。
ただし、大規模なアプリケーションでは有料プランが必要になる場合があります。
比較項目 | Devise | Auth0 |
---|---|---|
機能の豊富さ | ◯ Railsアプリケーションに適した豊富な機能を提供 | ◎ 認証に関する多くの機能を提供し、カスタマイズ性も高い |
導入の容易さ | ◎ Railsアプリケーションへの導入が非常に簡単 | ○ 導入はやや複雑だが、ドキュメントが充実している |
メンテナンス | ○ Gemのアップデートが必要だが、比較的安定している | ◎ Auth0側でメンテナンスを行うため、開発者の負担が少ない |
カスタマイズ性 | ○ Deviseの機能をカスタマイズすることが可能 | ◎ Auth0の管理画面で多くの設定やカスタマイズが可能 |
外部サービス連携 | △ OmniAuthを使って外部サービス連携が可能だが、設定が必要 | ◎ 多くの外部サービスとの連携が容易に可能 |
コスト | ◎ オープンソースで無料で利用可能 | △ 無料プランもあるが、大規模なアプリケーションでは有料プランが必要 |
スケーラビリティ | ○ アプリケーションのスケーリングに合わせて対応可能 | ◎ Auth0側でスケーリングを行うため、アプリケーションの規模に関係なく利用可能 |
セキュリティ | ○ 一般的な認証機能のセキュリティは確保されている | ◎ 専門的な認証サービスとして高いセキュリティを提供 |
◎:非常に優れている
○:優れている
△:状況によって異なる
まとめ
今回のように外部サービスを利用することで、比較的簡単に色々な機能を利用することができるため、開発者がアプリケーションの開発に集中することができます。
一方で、仕組みがわからないままアプリケーションに組み込んでしまっては、後のメンテナンスなどで非常に苦労することになりそうです。
アプリケーションの要件や規模、予算などを考慮して、適切なサービスを選択することの重要性を改めて感じました。
今後の展望
もともと、フロントエンドにNext.js ✖️ バックエンドにRailsをAPIとして利用した、Auth0による認証機能を実装したアプリケーションを作成したいと考えており、今回はその前段階のお試し実装でした。
APIの機序なども全くわかっていないため、まだまだ先のお話になりそうですが、ひとまず、Auth0のRails APIバージョンを作成しておおまかに流れを掴めたら良いなと思っています。
Discussion