LoginSignup
21
2

More than 1 year has passed since last update.

Railsアプリケーションの認証をdeviseからAuth0にリプレースした話

Last updated at Posted at 2022-12-05

はじめに

先日、弊社プロダクトのモチベーションクラウドのマイクロサービス化(認証基盤との接続)に成功しました!

今回は既存のRailsアプリケーションをマイクロサービス化するに当たってdeviseをリプレースした手順を記して、
是非みなさまのRailsアプリケーションのマイクロサービス化の助けになればと思います。

deviseの削除

Railsのログイン機能といえばRailsチュートリアルにも出てくるdeviseを利用しているプロダクトが多いと思います。
https://github.com/heartcombo/devise

このdeviseはcookieで認証情報を保持して、都度認証を行っています。
そしてdeviseは幾つかヘルパーメソッドがあり、これらの置き換えがメインになると思います。
https://github.com/heartcombo/devise#controller-filters-and-helpers

まずはこのヘルパーメソッドが使われている箇所がないか?を確認して、それらの置き換えを検討しました。
その結果、主に大変だった以下3つの代替方法を述べます。

- authenticate_user!
- current_user
- sign_out

authenticate_user!

認証してるユーザーかどうかを判定するバリデーションです。

今回認証基盤の移行に伴い、新しい認証方法として、Auth0を利用していますので、
公式が出しているドキュメントに則り、このメソッドを書き換えていきました。
※記載しているコードは公式のドキュメントの内容をそのまま持ってきています
https://auth0.com/docs/quickstart/backend/rails/01-authorization

# app/controllers/concerns/secured.rb
# frozen_string_literal: true
module Secured
  extend ActiveSupport::Concern
  included do
    before_action :authenticate_request!
  end
  private
  def authenticate_request!
    auth_token
  rescue JWT::VerificationError, JWT::DecodeError
    render json: { errors: ['Not Authenticated'] }, status: :unauthorized
  end
  def http_token
    if request.headers['Authorization'].present?
      request.headers['Authorization'].split(' ').last
    end
  end
  def auth_token
    JsonWebToken.verify(http_token)
  end
end

current_user

ログイン中のユーザーを取得するメソッドです。
これは先述のauthenticate_user!を呼んだ後に一意のユーザーを特定するidのようなものを
インスタンス変数で持っておいて、Userからfindする感じです。
こんなイメージ

def current_user
  # current_userを取得する前ならデコード済みのidからUserを引く
  # access_tokenからデコードする処理は別で定義
  @current_user ||= id_by_access_token ? User.find(@id) : nil
end

sign_out

Auth0のログアウトはFEから呼べるようになります。
こちらに関してもauth0-spa-jsというパッケージがあり、
ここで紹介されている様にlogoutを呼べます。
https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md

※こちらも記載しているコードは公式のドキュメントの内容をそのまま持ってきています

<button id="logout">Logout</button>
document.getElementById('logout').addEventListener('click', () => {
  auth0.logout();
});

RSpec

上記ヘルパーメソッドとは少し異なりますが、権限ごとのテストを行うべく、

  • ユーザーAでログイン
  • ユーザーAの権限では、○○ができる
  • ログアウト
  • ユーザーBでログイン
  • ユーザーBの権限では、○○ができない

みたいなテストケースもあったので、これらも置き換えなければなりません。
それらに対してはスタブ化することで、解決しました。

deviseをリプレースしてみて

deviseをリプレースして、他にも諸々対応を完了し、
認証基盤のマイクロサービス化したことで、弊社のプロダクト間のシングルサインオンが可能になりました。
いちいちログインしなくて良くなるのはとても素晴らしいことですね。

これからも沢山プロダクトを作っていく上で、
サービス間の組織や個人のデータを1つに集約できたのも、今後の可能性の広がりを感じます。

一方で辛かったことも同様にあり、よくマイクロサービスの課題として挙げられる
データ管理だったり、運用面は私たちも工夫が必要な点でした。

是非、自分のアプリケーションがどの構成に向いているのか?は一度吟味した上で、
マイクロサービスにするのか、モノリスで行くのかを決めると良いんじゃないかなって思います。
それではみなさん、良いお年を!!

21
2
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
21
2