こんにちは!シン・ゴジラをあと3回くらい見たい @sweep3092 です。
Railsでユーザ認証といえばもはやセットのようになっている devise + omniauth という構成が一般的ですが、 今回はありそうでなかなか情報が見つからない、Railsでモデルを持たずにさくっとユーザ認証をする話をしようと思います。
モデルを持たずにユーザ認証を実装するのは、なんと言っても既存のユーザ認証の仕組みとバッティングしにくいのがメリットです。 deviseを使うといろいろとイイカンジに設定してくれるのでとても便利ですが、別の管理のユーザ認証の仕組みを追加しようとしたりすると嵌まりがちです。 ここで原点に立ち返って、「devise使わないでもいいのでは?」となり、「そもそもモデル要らないのでは」となったのが本記事を書いたきっかけになります。
ユーザ認証の仕組みだけをさくっと提供するのが目的なので、認証したユーザを別のモデルとリレーションさせたりするのにはあまり向きませんが、 社内OAuthアカウントだけ認証できればいいから出来るだけ簡単に作りたい、といった場合にはモデルはなくても十分機能する場合も多いのではないでしょうか。
本記事では、omniauthのroutesやAPIキーの設定などの基本的な設定を済ませた前提で、モデルを持たないユーザ認証の仕組みを実現するControllerの書き方をご紹介いたします。
目的
- deviseも使わずモデルも持たずにomniauthでユーザ認証の仕組みを作る
- 社内アカウントのみ許可する
方法
今回はすでに User
というモデルが存在すると仮定して、 Staff
という別のユーザの概念をアプリケーションに持ち込むことを想定し、
Staff
専用のApplicationController, SessionsControllerを作ります。
このとき User
とバッティングしないように、namespaceを明示的に分けます。
SessionsController
omniauthのcallbackが帰ってくるcreateアクションでは、セッションに使いそうなユーザ情報を雑に入れておきます。 また、このとき「社内アカウントであるか」をチェックします。 今回はメールアドレスが独自ドメインのものかを確かめるようにしていますが、ここは用途に合わせて変更して頂くのが良いかと思います。
ApplicationController側でセッションをみてログイン済みかどうかを確認するので、ログアウトの際には reset_session
すればOKです。
class Staff::SessionsController < Staff::ApplicationController skip_action_callback :authenticate_staff! def login end def create auth = request.env['omniauth.auth'] # 社内アカウントじゃなければログイン画面に戻してエラー表示 unless auth.info.email.end_with? '@mycompany.co.jp' redirect_to staff_sessions_login_path, flash: {error: '社内アカウントのみ使用できます'} end # モデルなどに格納せず、sessionに使いそうなユーザ情報を雑に入れる session[:staff_uid] = auth.uid session[:staff_name] = auth.info.name session[:staff_email] = auth.info.email redirect_to staff_path end def destroy reset_session redirect_to staff_sessions_login_path end def failure redirect_to staff_sessions_login_path end end
ApplicationController
ここでは、 Staff
が認証済みであるかどうかを確認するメソッドを定義します。情報が欠けていたら reset_session
をしてログイン画面にリダイレクトします。
また、ログイン中の Staff
の情報を取得するヘルパメソッドを定義します。deviseで使える current_user
などと同じようなイメージです。
同様に、 staff_signed_in?
などのヘルパーメソッドも用意しておくと使い勝手が良いかと思います。
class Staff::ApplicationController < ActionController::Base helper_method :current_staff helper_method :staff_signed_in? before_action :authenticate_staff!, except: [:login] skip_action_callback :authenticate_staff! private def authenticate_staff! if session[:staff_uid].blank? || session[:staff_email].blank? || session[:staff_name].blank? reset_session redirect_to staff_sessions_login_path, flash: {error: 'ログインしてください'} end end def current_staff return nil if session[:staff_uid].blank? || session[:staff_email].blank? || session[:staff_name].blank? { uid: session[:staff_uid], email: session[:staff_email], name: session[:staff_name], } end def staff_signed_in? current_staff.present? end end
使い方
<p>ようこそ <%= current_staff[:name] %> さん</p>
とか
<% if staff_signed_in? %> <%= link_to 'logout', staff_sessions_destroy_path %> <% end %>
さいごに
やってみれば何の変哲も無い当たり前の超絶簡単なユーザ認証ですが、omniauthってどうやって使うんだっけ、と調べているとどうしてもdeviseを使うように流されてしまいがちのように思います。 ですが用途によってはRailsとは言ってもdeviseに頼らず、モデルに縛られずに原点に立ち返ってセッションのみでさくっとユーザ認証を済ませてしまうのもいいのではないでしょうか。
現在アクトキャットでは一緒に働いて頂けるメンバーを募集しています。 Webエンジニアの方、インフラエンジニアの方、Webデザイナー、マーケターの方を積極採用中です! 興味がある方はぜひWantedlyからご応募ください!