Edited at

Elixir, PhoenixでLoginページを作成

More than 3 years have passed since last update.

やりたいことはログインページでemailpasswordを入力して、ログインするとユーザー一覧ページに遷移します。



まずユーザー一覧ページを用意するためにPhoenixのEctoに関するドキュメントを読むといいです。

ログインページはネット上で探したものを使っています。その中にBootstrap3が含まれているので、Bootstrap3も使いたいです。自分のこの前の投稿を参照にするといいです。


  • プロジェクトを作成します。--no-brunchについての説明はここにあります。

13:29:11 [N1210A001 => ~/Playground/elixir]

$ mix phoenix.new hello_phoenix --no-brunch


  • ユーザー一覧のページを用意します。下のコマンドを実行するとhello_phoenix/priv/repo/migrations/ディレクトリの下にmigrationファイルが生成されて、後で使う$ mix ecto.migrateコマンドの為です。

13:34:30 [N1210A001 => ~/Playground/elixir/hello_phoenix]

$ mix phoenix.gen.html User users name:string email:string password:string


  • resources "/users", UserControllerhello_phoenix/web/router.exに追加します。


  • hello_phoenix_devデータベースを作成します。なぜhello_phoenix_devを作成するかはhello_phoenix/config/dev.exsファイルの中に定義されています。


postgresのroleがないなどのエラー出ている場合はこのページで答えは探せます。

13:37:18 [N1210A001 => ~/Playground/elixir/hello_phoenix]

$ mix ecto.create


  • 作成されたデーターベスにテーブルを作成します。

13:47:53 [N1210A001 => ~/Playground/elixir/hello_phoenix]

$ mix ecto.migrate


  • これでアプリを立ち上げてみます。下の図のようになっているはずです。

13:48:01 [N1210A001 => ~/Playground/elixir/hello_phoenix]

$ mix phoenix.server

* 画面上でユーザを複数を作成します。

1) hello_phoenix/web/templates/layout/application.html.eexを下のように修正します。

 <!DOCTYPE html>

<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">

<title>Hello Phoenix!</title>
<link rel="stylesheet" href="<%= static_path(@conn, "/css/bootstrap.css") %>">
<link rel="stylesheet" href="<%= static_path(@conn, "/css/login.css") %>">
<link rel="stylesheet" href="<%= static_path(@conn, "/js/bootstrap.js") %>">
</head>

<body>
<%= @inner %>
</body>
</html>

2) hello_phoenix/web/templates/page/index.html.eexを下のように修正します。

 <div class="container">

<div class="row">
<div class="col-sm-6 col-md-4 col-md-offset-4">
<div class="account-wall">
<form class="form-signin" action="<%= page_path(@conn, :login) %>" method="post">
<input type="text" class="form-control" name="user[email]" placeholder="Email" required autofocus>
<input type="password" class="form-control" name="user[password]" placeholder="Password" required>
<input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>">
<button class="btn btn-lg btn-primary btn-block" type="submit">
Sign in</button>
<label class="checkbox pull-left">
<input type="checkbox" value="remember-me">
Remember me
</label>
<a href="#" class="pull-right need-help">Need help? </a><span class="clearfix"></span>
</form>
</div>
<a href="#" class="text-center new-account">Create an account </a>
</div>
</div>
</div>

なぜ<input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>">を入れているかはstackoverflowの質問を参照するといいです。この1行を入れないと、下のようなエラーが出ます。

invalid CSRF (Cross Site Forgery Protection) token, make sure all requests include a '_csrf_token' param or an 'x-csrf-token' header

3) login.cssファイルを下の中身で作成して、hello_phoenix/priv/static/css/ディレクトリ下に移動します。

.form-signin

{
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-signin .form-signin-heading, .form-signin .checkbox
{
margin-bottom: 10px;
}
.form-signin .checkbox
{
font-weight: normal;
}
.form-signin .form-control
{
position: relative;
font-size: 16px;
height: auto;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.form-signin .form-control:focus
{
z-index: 2;
}
.form-signin input[type="text"]
{
margin-bottom: -1px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.form-signin input[type="password"]
{
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.account-wall
{
margin-top: 20px;
padding: 40px 0px 20px 0px;
background-color: #f7f7f7;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.login-title
{
color: #555;
font-size: 18px;
font-weight: 400;
display: block;
}
.profile-img
{
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
.need-help
{
margin-top: 10px;
}
.new-account
{
display: block;
margin-top: 10px;
}

4) hello_phoenix/web/router.exファイルに/loginを部分を追加して、下のようになります。注意して欲しいのはpostを使っています。

 defmodule HelloPhoenix.Router do

use HelloPhoenix.Web, :router

pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
end

pipeline :api do
plug :accepts, ["json"]
end

scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack

get "/", PageController, :index
post "/login", PageController, :login
resources "/users", UserController
end
end

5) これでアプリを起動して、ログインページが表示されるようになっているはずです。

14:28:36 [N1210A001 => ~/Playground/elixir/hello_phoenix]

$ mix phoenix.server


  • これからログイン処理に入ります。hello_phoenix/web/controllers/page_controller.exファイルを以下のように修正します。

 defmodule HelloPhoenix.PageController do

use HelloPhoenix.Web, :controller

# `query = from u in User,`部分
# の`User`が使える為にaliasしている

alias HelloPhoenix.User

# `redirect conn, to: Helpers.user_path(conn, :index)`部分
# の`Helpers.user_path`が使えるためにaliasをしている

alias HelloPhoenix.Router.Helpers

plug :action

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

def login(conn, %{"user" => %{"email" => email, "password" => password}}) do
query = from u in User,
where: u.email == ^email,
where: u.password == ^password,
select: u.id
result = HelloPhoenix.Repo.all(query)
# ユーザーが存在すればユーザー一覧ページにリダイレクトされます
case length(result) > 0 do
true ->
redirect conn, to: Helpers.user_path(conn, :index)
false ->
text conn, "ログイン失敗"
end
end
end

これで一番簡単なログインページができました。また実装していない部分は

1) パスワードの暗号化

2) ログインしていないユーザーはユーザー一覧を見られないように

どなたか上のような機能実装したら、教えてください。特に2)番目です。