Addictを使ってPhoenixでお手軽ユーザー認証


## 概要
Phoenixにユーザー登録と認証を提供してくれるAddictを使ってお手軽にユーザー認証機能を実装します。

__[trenpixster/addict: User management lib for Phoenix Framework](https://github.com/trenpixster/addict)__

Addictはユーザー登録、ログイン、ログアウト、パスワードリセット、パスワードリカバリといった機能を提供しており、Railsで言うところのdeviseみたいなものだという認識でいいかと思います。

また、mixコマンドによるジェネレータにより、認証周りのviewテンプレートも生成できるため、お手軽に認証画面を作ることができます。

## 下準備
まず、phoenixのプロジェクトから作成していきます

```bash
$ mix phoenix.new user_auth_tutorial
$ cd user_auth_tutorial
$ mix ecto.create
```

Addictでは最低限Userモデルと、カラムにemailとencrypted_passwordが必要です。

またジェネレータにより生成されるテンプレートにはnameが含まれているため、namekカラムも含めておきます。

```bash
$ mix phoenix.gen.model User users email name encrypted_password
$ mix ecto.migrate
```

## Addictの導入
それではついに、addictを導入します。
mixファイルにaddictを追加します。

depsとapplicationの二箇所に追記しましょう。

```elixir:mix.exs
...

def application do
    [mod: {AddictTutorial, []},
     applications: [:phoenix, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :postgrex, :addict]]
  end

...

defp deps do
  ...
  {:cowboy, "~> 1.0"},
  {:addict, "~> 0.2"}]
end

...
```

追記したらAddictを含むライブラリをダウンロードします

```bash
$ mix deps.get
```

### Addictの設定

次に、mixコマンドにより提供されているconfigの生成を行います。

今回はMailgunを使わないので、最後のMailgunを使うかというところだけnoにしておきます。

```bash
$ mix addict.generate.configs

...

==> user_auth_tutorial
[o] Generating Addict configuration
Is your application root module UserAuthTutorial? [Yn]
Is your Ecto Repository module UserAuthTutorial.Repo? [Yn]
Is your User Schema module UserAuthTutorial.User? [Yn]
Will you be using Mailgun? [Yn] n
[o] Done!
```

### boilerplateの生成
最初にも書いたとおり、Addictはmixコマンドによるジェネレータにより、認証周りのviewテンプレートを生成してくれます。

ちなみに必須ではありませんのでviewを自分で実装をしたい場合は生成しなくて構いません

```bash
$ mix addict.generate.boilerplate
```

__注意__
boilerplateの中で使われているjqueryですが、呼び出し先のjqueryファイルはローカルのものになっているため、jqueryを配置するかCDNのパスに書き換える必要があります。

今回はCDNを使いますので、以下のようになるように書き換えましょう。

```elixir:web/templates/addict/addict.html.eex
...

    </div> <!-- /container -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
    <script src="<%= static_path(@conn, "/js/addict.js") %>"></script>
  </body>
</html>
```

### ルーティングの記述
routerにAddict用のルーティングを記述します。

ちなみにここのscopeはUserAuthTutorialとは別になりますのでデフォルトで記述されているscopeとは別で追加しましょう。

```elixir:web/router.ex
defmodule YourApp.Router do
  (...)
  use Addict.RoutesHelper
  (...)
  scope "/" do
    addict :routes
  end
end
```

Addictが提供するルーティングが追加されているか確認しましょう。

```bash
$ mix phoenix.routes
        register_path  POST  /register          Addict.AddictController :register
        register_path  GET   /register          Addict.AddictController :register
           login_path  POST  /login             Addict.AddictController :login
           login_path  GET   /login             Addict.AddictController :login
          logout_path  POST  /logout            Addict.AddictController :logout
          logout_path  GET   /logout            Addict.AddictController :logout
recover_password_path  POST  /recover_password  Addict.AddictController :recover_password
recover_password_path  GET   /recover_password  Addict.AddictController :recover_password
  reset_password_path  POST  /reset_password    Addict.AddictController :reset_password
  reset_password_path  GET   /reset_password    Addict.AddictController :reset_password
            page_path  GET   /                  UserAuthTutorial.PageController :index
```

## ユーザー認証を試す
ここまでで下準備とAddictの導入が完了しました。

後はphoenix.serverを起動して、アクセスするだけです。

```bash
$ mix phoenix.server
```

まず、ユーザー登録してみます
`http://localhost:4000/register`にアクセスします

![](https://gyazo.com/aaad96ba098a5a8d10da5573a27d59ce.jpg)

無事に`/`にリダイレクトが完了すればユーザー登録は完了です

今度はログインをしてみましょう
`http://localhost:4000/login`にアクセスします

![](https://gyazo.com/1dcaaea1ee683072366d0dae8f0800f2.jpg)

ログインも`/`にリダイレクトが完了すればログイン完了です。

## 認証のチェック
ログイン後でないとアクセスできないページを作る場合、ログインしていないユーザーはログインページへリダイレクトしたいです。

今回はトップページへのアクセスを制限します。
controllerでの認証のチェックは以下のように書けます

```elixir:web/controllers/page_controller.ex
defmodule UserAuthTutorial.PageController do
  use UserAuthTutorial.Web, :controller
  plug Addict.Plugs.Authenticated when action in [:index]

  def index(conn, _params) do
    render conn, "index.html"
  end
end
```

シークレットウィンドウなど、セッションのないブラウザから`http://localhost:4000`にアクセスすると、`/login`にリダイレクトされるのが確認できるかと思います。

## まとめ
AddictによりPhoenixに簡単にユーザー認証が実装できました。

実は、[Ueberauth](https://github.com/ueberauth/ueberauth)と[UeberauthIdentity](https://github.com/ueberauth/ueberauth_identity)でのメールアドレス、パスワード認証も試してみたのですが、今回のように簡単な認証を実装する場合はこちらの方がお手軽でいいかと思います。

ちなみに、Addictはhelperにより、current_userの取得なども提供されています。

[addict/helper.ex at master · trenpixster/addict](https://github.com/trenpixster/addict/blob/master/lib/addict/helper.ex)