LoginSignup
39
25

More than 3 years have passed since last update.

Rails 6 で omniauth-cognito-idp を使って Amazon Cognito 認証を実装するサンプル

Last updated at Posted at 2020-08-30

要点

Amazon Cognitoを使えば、deviseに依存せずに、ユーザ登録・ログイン・ログアウト・パスワードリセット・ソーシャルログイン・n段階認証・SAMLなど、様々な機能がアプリケーションコードから分離するかたちで追加可能です。Amazon Cognitoの他にも、Auth0やFirebase Authentication等があり、IDaaS(Identity as a Service)と呼ばれます。

本記事では、Railsアプリケーションで動作検証をする場合の手順を記載しています。

  1. Amazon Cognitoのユーザープールの作成とクライアントの設定の基本的な手順を解説(作業時間: 10分程度)
  2. 動作検証するためのサンプルアプリの実装方法を解決(作業時間: 10分程度)

なお、記事中のスクリーンショットに記載されたクライアントIDやシークレットは、既に削除されているため利用することはできません。ご自身で設定して動作検証してみてください。

環境

% ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]

% bin/rails version
Rails 6.0.3.2

手順1: ユーザープールの作成とクライアントの設定

作業時間: 10分程度

Amazon Cognito のコンソールから「ユーザープールを作成する」を押下

Screenshot from 2020-08-30 12-33-26

プール名を入力

サンプルなのでデフォルトを確認するを押下

Screenshot from 2020-08-30 11-48-21

プールの作成

Screenshot from 2020-08-30 11-51-25

作成完了

プール ID をメモする:

Screenshot from 2020-08-30 11-53-53

ドメイン名を設定

ナビゲーションの ドメイン名 をクリックし、認証フォームのURLを設定。設定した、 https://{your prefix}.auth.ap-northeast-1.amazoncognito.com をメモする:

Screenshot from 2020-08-30 11-55-48

アプリクライアントの作成

ナビゲーションの アプリクライアント をクリックし、 アプリクライアントの追加 をクリック:

Screenshot from 2020-08-30 12-00-18

Screenshot from 2020-08-30 12-01-25

アプリクライアントIDアプリクライアントのシークレット をメモ:

Screenshot from 2020-08-30 12-02-23

アプリクライアントの設定

ナビゲーションの アプリクライアントの設定を押下し、コールバックURLとサインアウトURLを設定(それ以外の設定はスクリーンショットを参照):

Screenshot from 2020-08-30 12-04-49

これでcognito側の設定は完了です(なお、スクリーンショットの値は利用できません)。

手順2: アプリケーションの実装

作業時間: 10分程度

rails new

サンプルなので割愛

omniauth-cognito-idp を追加

gem 'omniauth-cognito-idp'

クレデンシャルの追加

今回はサンプルなので development で、ユーザプール作成時に生成した諸々をセットする:

$ bin/rails credentials:edit -e development
aws:
  access_key_id: 123
  secret_access_key: 345
  # 上記でメモした「ドメイン名」に含まれるリージョン
  region: ap-northeast-1
  # 上記でメモした「アプリクライアントID」
  cognito_client_id: *****YOUR CLIENT ID*****
  # 上記でメモした「アプリクライアントのシークレット」
  cognito_client_secret: *****YOUR SECRET*****
  # 上記でメモした「ドメイン名」
  cognito_user_pool_site: https://*****YOUR PREFIX*****.auth.ap-northeast-1.amazoncognito.com
  # 上記でメモした「プールID」
  cognito_user_pool_id: *****YOUR POOL ID*****

イニシャライザの追加

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider(
    :cognito_idp,
    Rails.application.credentials.aws[:cognito_client_id],
    Rails.application.credentials.aws[:cognito_client_secret],
    client_options: {
      site: Rails.application.credentials.aws[:cognito_user_pool_site]
    },
    scope: 'email openid',
    user_pool_id: Rails.application.credentials.aws[:cognito_user_pool_id],
    aws_region: Rails.application.credentials.aws[:region],
  )
end

HomeControllerの実装

root で表示する画面:

$ bin/rails g controller home show --skip-assets --skip-helper
<h1>Home#show</h1>
<p>Find me in app/views/home/show.html.erb</p>

<h1>RoR Cognito Sample</h1>
<p>Step 1 - Login.</p>
<%= button_to 'Login', 'auth/cognito-idp', method: :post %>
# config/routes.rb
Rails.application.routes.draw do
  root 'home#show'
end

CognitoIdpControllerの実装

OmniAuthで認証後の処理をするコールバック:

$ bin/rails g controller cognito_idp --skip-template-engine --skip-assets --skip-helper
class CognitoIdpController < ApplicationController
  def callback
    # 実際は provider と uid を使って、Userレコードを作成/参照し、user_id をsessionにセットするが
    # サンプルなのでauth hashをセット
    session[:userinfo] = request.env['omniauth.auth']

    redirect_to '/dashboard'
  end
end
# config/routes.rb
Rails.application.routes.draw do
  root 'home#show'
  get 'auth/cognito-idp/callback' => 'cognito_idp#callback'
end

セッションストアでCookieを利用して session[:userinfo] をセットしようとすると最大容量を超過するので、セッションストアをメモリに変更:

# config/initializers/session_store.rb
Rails.application.config.session_store :cache_store

config/environments/development.rbconfig.cache_store = :memory_store を追加。

ApplicationControllerに認証に関する振る舞いの追加:

実際はcurrent_userなども実装するがサンプルなのでuserinfoがsessionにセットされているかどうかを確認:

class ApplicationController < ActionController::Base
  private

  def authenticate_user!
    return redirect_to(root_path) unless signed_in?
  end

  def signed_in?
    session[:userinfo].present?
  end

  helper_method :signed_in?
end

DashboardControllerの実装

ログイン後の画面を実装する:

$ bin/rails g controller dashboard show --skip-assets --skip-helper
class DashboardController < ApplicationController
  before_action :authenticate_user!

  def show
  end
end
# config/routes.rb
Rails.application.routes.draw do
  root 'home#show'
  get 'auth/cognito-idp/callback' => 'cognito_idp#callback'
  get 'dashboard' => 'dashboard#show'
end
<h1>Dashboard#show</h1>
<p>Find me in app/views/dashboard/show.html.erb</p>
<p><%= session[:userinfo].inspect %></p>

<p><%= link_to 'logout', logout_path, method: :delete %></p>

SessionsControllerの実装:

ログアウト処理を実装(cognito側もログアウトする必要がある):

$ bin/rails g controller sessions --skip-template-engine --skip-assets --skip-helper
class SessionsController < ApplicationController
  before_action :authenticate_user!

  def destroy
    reset_session
    redirect_to cognito_logout_url
  end
end

direct ルーティングを使って、cognito側のログアウトを実装:

# config/routes.rb
Rails.application.routes.draw do
  root 'home#show'
  get 'auth/cognito-idp/callback' => 'cognito_idp#callback'
  get 'dashboard' => 'dashboard#show'
  delete 'logout' => 'sessions#destroy'

  direct :cognito_logout do
    query = {
      client_id: Rails.application.credentials.aws[:cognito_client_id],
      logout_uri: root_url,
    }.to_param
    "#{Rails.application.credentials.aws[:cognito_user_pool_site]}/logout?#{query}"
  end
end

動作検証

rails server を起動して localhost:3000 にアクセス:

ルートを表示

Login を押下:

Screenshot from 2020-08-30 12-11-06

cognitoのログインフォームが表示されるのでサインアップする

Screenshot from 2020-08-30 12-13-05

Screenshot from 2020-08-30 12-14-22

メールアドレスを確認して認証コードを入力するとログインが完了します。

Screenshot from 2020-08-30 12-16-44

参考

以上

39
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
25