はじめに
先日、弊社プロダクトのモチベーションクラウドのマイクロサービス化(認証基盤との接続)に成功しました!
今回は既存の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つに集約できたのも、今後の可能性の広がりを感じます。
一方で辛かったことも同様にあり、よくマイクロサービスの課題として挙げられる
データ管理だったり、運用面は私たちも工夫が必要な点でした。
是非、自分のアプリケーションがどの構成に向いているのか?は一度吟味した上で、
マイクロサービスにするのか、モノリスで行くのかを決めると良いんじゃないかなって思います。
それではみなさん、良いお年を!!