Goal
ログイン(サインイン)用のフォームを作成する。
Authenticationの処理を作成する。
Authenticationの処理を作成する。
Dev-Environment
OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Phoenix Framework: v0.13.1
PostgreSQL: postgres (PostgreSQL) 9.4.4
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Phoenix Framework: v0.13.1
PostgreSQL: postgres (PostgreSQL) 9.4.4
Wait a minute
第八章は、ログインフォームとAuthenticationから始める。
難しい部分は後に回し、まずは表示部分から作成する。
難しい部分は後に回し、まずは表示部分から作成する。
Index
- Session Controller
- Login Form
- Authentication
- Extra
1. Session Controller
Rails Tutorialの例に倣い、
Sessionのコントローラを作成する。
Sessionのコントローラを作成する。
各処理をRESTfulに対応させます。
- サインインページ: new
- サインイン: create
- サインアウト: delete
それぞれのルーティングを追加。
ファイル: web/router.ex
ファイル: web/router.ex
scope "/", SampleApp do
...
get "/signin", SessionController, :new
post "/session", SessionController, :create
delete "/signout", SessionController, :delete
end
ルーティングを確認。
>mix phoenix.routes
...
session_path GET /signin SampleApp.SessionController.new/2
session_path POST /session SampleApp.SessionController.create/2
session_path DELETE /signout SampleApp.SessionController.delete/2
Sessionコントローラを作成。
ファイル: web/controllers/session_controller.ex
ファイル: web/controllers/session_controller.ex
defmodule SampleApp.SessionController do
use SampleApp.Web, :controller
plug :action
def new(conn, _params) do
render conn, "login_form.html"
end
def create(conn, _params) do
redirect(conn, to: static_pages_path(conn, :home))
end
def delete(conn, _params) do
redirect(conn, to: static_pages_path(conn, :home))
end
end
続いて、ビューと仮のテンプレートも作成。
ファイル: web/views/session_view.ex
ファイル: web/views/session_view.ex
defmodule SampleApp.SessionView do
use SampleApp.Web, :view
end
ファイル: web/templates/session/login_form.html.eex
<div class="jumbotron">
<h2>Sign in!!</h2>
</div>
実行して画面を確認する。
URL Example: http://localhost:4000/signin
URL Example: http://localhost:4000/signin
Caution:
create、deleteアクションは、この段階では実行エラーが発生する。
create、deleteアクションは、この段階では実行エラーが発生する。
2. Login Form
次はログインフォームを作成していく。
経験ある方は、
どのようなテンプレートになるか想像が付いているのではないだろうか?
どのようなテンプレートになるか想像が付いているのではないだろうか?
ファイル: web/templates/session/login_form.html.eex
<h1>Sign in!!</h1>
<%= form_for @conn, session_path(@conn, :create), [name: :login_params], fn f -> %>
<%= if f.errors != [] do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below:</p>
<ul>
<%= for {attr, message} <- f.errors do %>
<li><%= humanize(attr) %> <%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<label>Email</label>
<%= text_input f, :email, class: "form-control" %>
</div>
<div class="form-group">
<label>Password</label>
<%= text_input f, :password, class: "form-control" %>
</div>
<div class="form-group">
<%= submit "Submit", class: "btn btn-primary" %>
</div>
<% end %>
画面を確認するとフォーム画面が表示されている。
Description:
この時点でSubmitのボタンを押下すると、
createアクションが実行され/homeへリダイレクトする。
この時点でSubmitのボタンを押下すると、
createアクションが実行され/homeへリダイレクトする。
3. Authentication
ログイン(サインイン)と切っても切り離せない認証を作成する。
集中力も切れてくる頃合いだろうが、もう少しお付き合い頂ければと思う。
集中力も切れてくる頃合いだろうが、もう少しお付き合い頂ければと思う。
まず行うのは、認証で使うEmailでDBからデータを取得できるようにすることだ。
自分で作成しないと、Repoでid以外からDBデータを取得できない。
(方法を知っている方がいましたらご教授頂ければ嬉しいです)
自分で作成しないと、Repoでid以外からDBデータを取得できない。
(方法を知っている方がいましたらご教授頂ければ嬉しいです)
Ecto.Queryのインポートと関数を追加する。
ファイル: web/models/user.ex
ファイル: web/models/user.ex
import Ecto.Query
def find_user_from_email(email) do
query = from user in SampleApp.User,
where: user.email == ^email,
select: user
SampleApp.Repo.all(query) |> List.first
end
ファイル: web/controllers/session_controller.ex
認証を行う関数を定義する。
createアクションで認証の処理を行う。
認証を行う関数を定義する。
createアクションで認証の処理を行う。
ログインを確認する関数。
def login(email, password) do
user = SampleApp.User.find_user_from_email(email)
case authentication(user, password) do
true -> {:ok, user}
_ -> :error
end
end
認証を行う関数。
def authentication(user, password) do
case user do
nil -> false
_ -> Safetybox.is_decrypted(password, user.password_digest)
end
end
createアクションでの処理。
成功と失敗で処理を分けている。
成功と失敗で処理を分けている。
def create(conn, %{"login_params" => %{"email" => email, "password" => password}}) do
case login(email, password) do
{:ok, user} ->
conn
|> put_flash(:info, "User login is success!!")
|> redirect(to: static_pages_path(conn, :home))
:error ->
conn
|> put_flash(:error, "User login is failed!! email or password is incorrect.")
|> redirect(to: session_path(conn, :new))
end
end
Authenticationの処理だが、後の内容で再登場する予定である。
Plugに組み込んだ認証処理を行うため。
Sessionとの絡みがあるので今回は暫定的な処理として作成している。
Plugに組み込んだ認証処理を行うため。
Sessionとの絡みがあるので今回は暫定的な処理として作成している。
4. Extra
以前レイアウトのヘッダーで、
sign inのリンクを作成していたことを覚えているだろうか?
sign inのリンクを作成していたことを覚えているだろうか?
忘れないうちにリンク先を#から書き換えます。
ファイル: web/templates/layout/header.html.eex
ファイル: web/templates/layout/header.html.eex
変更前:
<li><a href=#>Sign in</a></li>
変更後:
<li><a href="<%= session_path(@conn, :new) %>">Sign in</a></li>
それと、密かに用意していたUserControllerのauthenticationメソッドを削除します。
(不要でした申し訳ないです・・・しかもそのまま使えないバグのおまけ付き・・・笑えない)
(不要でした申し訳ないです・・・しかもそのまま使えないバグのおまけ付き・・・笑えない)
ファイル: web/controllers/user_controller.ex
def authentication(email, password) do
user = Repo.get(SampleApp.User, email)
Safetybox.is_decrypted(password, user.password_digest)
end
Speaking to oneself
今回はここまでです。
次は、Phoenix - Guide Sessionsを参考にSessionについて学びます。
次は、Phoenix - Guide Sessionsを参考にSessionについて学びます。
PhoenixでSessionを扱うためにはPlugを学ぶのが良いのですが、
機能を利用することを優先します。
機能を利用することを優先します。
正直な話、Plugは機能が多いので紹介するのは中々大変です。
機能の多さはドキュメントを見て頂ければ分かるかと(笑)
なので、Plugについて遊ぶ記事はまた別で作成します。
機能の多さはドキュメントを見て頂ければ分かるかと(笑)
なので、Plugについて遊ぶ記事はまた別で作成します。
Plugを理解できれば、できる幅が広がると思います。