ex_adminは、Railsのactiveadminと同様なCRUD画面を簡単に作成できる非常に便利なパッケージです。
READMEでは説明されていませんが、ElixirのProtocol機能を使用して、ueberauth等の認証パッケージとの連携が可能ですのでその方法について解説したいと思います。
手順
ueberauthによる認証の実装方法から説明するとかなり長くなってしまうため、ueberauth_exampleに対してex_adminを組み込む方法を説明したいと思います。
1. ueberauth_exampleの取得
まず、下記からueberauth_exampleを取得してください。
2. ex_adminのインストール
次に、上記のueberauth_exampleプロジェクトに対してex_adminをインストールしてください。
上記のex_adminのREADMEのうち、config.exsの設定部分まで完了させた上で、iex -S mix phoenix.server
でアプリケーションを起動し、http://localhost:4000/admin
にアクセスしてダッシュボードが表示されることを確認してください。
3. Plug.ConnモジュールにExAdmin.Authenticationプロトコルを実装
どこの位置でもいい(例えばwebディレクトリの直下等)ので、下記のようなファイルを作成してください。
# conn.ex
defimpl ExAdmin.Authentication, for: Plug.Conn do
import Plug.Conn, only: [get_session: 2]
import UeberauthExample.Router.Helpers
def use_authentication?(_), do: true
def current_user(conn) do
get_session(conn, :current_user)
end
def current_user_name(conn) do
current_user(conn).name
end
def session_path(conn, _action) do
auth_path(conn, :delete)
end
end
このファイルが追加された状態で、ueberauth_exampleアプリケーションにログインし、http://localhost:4000/admin
にアクセスしてみてください。画面右上に、下記のように「ユーザー名」と「Logout」リンクが追加されていると思います。
Logoutリンクをクリックすると、ログアウトされてトップページにリダイレクトされることを確認してください。
4. ログイン検証用無名関数の追加
上記までの作業により、管理画面にログインユーザーを表示してログアウトする機能までは作成出来ましたが、ログインしていないユーザーも管理画面にアクセス出来てしまう状態なので、ex_adminの設定に、ログイン検証用の無名関数を追加します。
- 注:この機能はDashboard(register_page関数で作成される静的ページ)だとうまく動作しないので、何か適当なModelを作成して、それに対する管理画面を追加して作業を進めてください。下記では「Hoge」というモデルとそれに対応する管理画面が追加されたという前提で説明いたします。
# config.exs
config :ex_admin,
repo: UeberauthExample.Repo,
module: UeberauthExample,
modules: [
# UeberauthExample.ExAdmin.Dashboard, # Dashboardはコメントアウトしてください。
UeberauthExample.ExAdmin.Hoge
],
# 下記を追加
authorize: fn(conn, action, resource_model) ->
UeberauthExample.UserAuth.check_logged_in(conn, action, resource_model)
end
# user_auth.ex
defmodule UeberauthExample.UserAuth do
import UeberauthExample.Router.Helpers
import Plug.Conn, only: [get_session: 2]
import Phoenix.Controller, only: [redirect: 2]
def logged_in?(conn) do
case current_user(conn) do
nil -> false
_ -> true
end
end
def current_user(conn) do
get_session(conn, :current_user)
end
def check_logged_in(conn, _action, _resource_model) do
if conn.request_path != auth_path(conn, :request) && !logged_in?(conn) do
conn |> redirect(to: auth_path(conn, :request))
end
true
end
end
上記を追加して、ログインしていない状態でhttp://localhost:4000/admin/hoges
にアクセスしてみてください。ログイン画面にリダイレクトされると思います。
解説
Plug.Connモジュールに対してExAdmin.Authenticationプロトコルを実装した箇所がちょっと分かりにくいと思いますので解説します。
ex_adminには下記のようなファイルが存在しています。
# lib/ex_admin/authentication.ex
defprotocol ExAdmin.Authentication do
@fallback_to_any true
def use_authentication?(conn)
def current_user(conn)
def current_user_name(conn)
def session_path(conn, action)
end
defimpl ExAdmin.Authentication, for: Any do
def use_authentication?(_), do: false
def current_user(_), do: nil
def current_user_name(_), do: nil
def session_path(_, _), do: ""
end
上記がビューでimportされて
# web/views/layout_view.ex
defmodule ExAdmin.LayoutView do
...
import ExAdmin.Authentication
...
end
テンプレートファイルで使用されます。
# templates/layout/admin.html.eex
<%= if use_authentication?(@conn) do %>
<p class="header-item" id="utility_nav">
<span class="current_user"><%= current_user_name(@conn) %></span>
</p>
<% end %>
Plug.Conn
に対してExAdmin.Authenticationプロトコルを実装していない場合、上記関数の呼び出しはAny
にフォールバックしますが、Plug.Conn
に対するプロトコルの実装を追加するとそちらが実行されるようになる、という仕組みのようです。
プロトコルのAnyへのフォールバック機能に関しては下記で説明されています。
まとめ
かなり省略して説明してありますので、上記だけだとうまく動作しない箇所があるかもしれませんが、ご容赦頂ければと思いますm(__)m