devise-compatible sessions

This commit is contained in:
byte[] 2019-08-17 14:58:36 -04:00
parent 5de52848c6
commit 8ae0853890
11 changed files with 122 additions and 33 deletions

View file

@ -13,6 +13,10 @@ config :philomena,
config :philomena, config :philomena,
password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP" password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP"
config :philomena, :pow,
user: Philomena.Users.User,
repo: Philomena.Repo
config :bcrypt_elixir, config :bcrypt_elixir,
log_rounds: 12 log_rounds: 12

View file

@ -0,0 +1,13 @@
defmodule Philomena.Users.Password do
def hash_pwd_salt(password, opts \\ []) do
pepper = Application.get_env(:philomena, :password_pepper)
Bcrypt.hash_pwd_salt(<<password::binary, pepper::binary>>, opts)
end
def verify_pass(password, stored_hash) do
pepper = Application.get_env(:philomena, :password_pepper)
Bcrypt.verify_pass(<<password::binary, pepper::binary>>, stored_hash)
end
end

View file

@ -1,10 +1,17 @@
defmodule Philomena.Users.User do defmodule Philomena.Users.User do
alias Philomena.Users.Password
use Ecto.Schema use Ecto.Schema
use Pow.Ecto.Schema,
password_hash_methods: {&Password.hash_pwd_salt/1, &Password.verify_pass/2}
import Ecto.Changeset import Ecto.Changeset
schema "users" do schema "users" do
field :email, :string field :email, :string
field :encrypted_password, :string, default: "" field :encrypted_password, :string
field :password_hash, :string, source: :encrypted_password
field :reset_password_token, :string field :reset_password_token, :string
field :reset_password_sent_at, :naive_datetime field :reset_password_sent_at, :naive_datetime
field :remember_created_at, :naive_datetime field :remember_created_at, :naive_datetime
@ -13,12 +20,17 @@ defmodule Philomena.Users.User do
field :last_sign_in_at, :naive_datetime field :last_sign_in_at, :naive_datetime
field :current_sign_in_ip, EctoNetwork.INET field :current_sign_in_ip, EctoNetwork.INET
field :last_sign_in_ip, EctoNetwork.INET field :last_sign_in_ip, EctoNetwork.INET
field :name, :string
pow_user_fields()
timestamps(inserted_at: :created_at) timestamps(inserted_at: :created_at)
end end
@doc false @doc false
def changeset(user, attrs) do def changeset(user, attrs) do
user user
|> pow_changeset(attrs)
|> cast(attrs, []) |> cast(attrs, [])
|> validate_required([]) |> validate_required([])
end end

View file

@ -35,6 +35,7 @@ defmodule PhilomenaWeb do
# Import convenience functions from controllers # Import convenience functions from controllers
import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1] import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
import Pow.Plug, only: [current_user: 1]
# Use all HTML functionality (forms, tags, etc) # Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML use Phoenix.HTML

View file

@ -43,6 +43,8 @@ defmodule PhilomenaWeb.Endpoint do
signing_salt: "signed cookie", signing_salt: "signed cookie",
encryption_salt: "authenticated encrypted cookie" encryption_salt: "authenticated encrypted cookie"
plug Philomena.Plugs.Session, otp_app: :philomena
plug PhilomenaWeb.Plugs.RenderTime plug PhilomenaWeb.Plugs.RenderTime
plug PhilomenaWeb.Router plug PhilomenaWeb.Router
end end

View file

@ -0,0 +1,52 @@
defmodule Philomena.Plugs.Session do
use Pow.Plug.Base
alias Plug.Conn
alias Philomena.{Repo, Users.User}
@session_key :philomena_session
def fetch(conn, _config) do
conn = Conn.fetch_session(conn)
user = Conn.get_session(conn, @session_key)
conn
|> maybe_load_user(user)
end
def create(conn, user, _config) do
user = session_value(user)
conn =
conn
|> Conn.fetch_session()
|> Conn.put_session(@session_key, user)
{conn, user}
end
def delete(conn, _config) do
conn
|> Conn.fetch_session()
|> Conn.delete_session(@session_key)
end
defp maybe_load_user(conn, {:ok, user}) do
with {:ok, [user_id, hash]} <- Jason.decode(user),
%User{} = user <- Repo.get(User, user_id),
^hash <- binary_part(user.encrypted_password, 0, 25)
do
{conn, user}
else
_ ->
{conn, nil}
end
end
defp maybe_load_user(conn, _) do
{conn, nil}
end
defp session_value(user) do
Jason.encode([user.id, binary_part(user.encrypted_password, 0, 25)])
end
end

View file

@ -1,5 +1,6 @@
defmodule PhilomenaWeb.Router do defmodule PhilomenaWeb.Router do
use PhilomenaWeb, :router use PhilomenaWeb, :router
use Pow.Phoenix.Router
pipeline :browser do pipeline :browser do
plug :accepts, ["html"] plug :accepts, ["html"]
@ -13,6 +14,12 @@ defmodule PhilomenaWeb.Router do
plug :accepts, ["json"] plug :accepts, ["json"]
end end
scope "/" do
pipe_through :browser
pow_routes()
end
scope "/", PhilomenaWeb do scope "/", PhilomenaWeb do
pipe_through :browser pipe_through :browser

View file

@ -1,31 +0,0 @@
<!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.0"/>
<title>Philomena · Phoenix Framework</title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
</head>
<body>
<header>
<section class="container">
<nav role="navigation">
<ul>
<li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
</ul>
</nav>
<a href="http://phoenixframework.org/" class="phx-logo">
<img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
</a>
</section>
</header>
<main role="main" class="container">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= render @view_module, @view_template, assigns %>
<p>Rendered in <%= render_time(@conn) %> ms</p>
</main>
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</body>
</html>

View file

@ -0,0 +1,24 @@
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.0"
title
= if assigns[:title] do
=> assigns[:title]
' - Philomena
- else
' Philomena
link rel="stylesheet" href=Routes.static_path(@conn, "/css/app.css")
body
= if @current_user do
p
' Welcome
= @current_user.name
= render @view_module, @view_template, assigns
p
' Rendered in
=> render_time(@conn)
' ms
script type="text/javascript" src=Routes.static_path(@conn, "/js/app.js")

View file

@ -45,7 +45,8 @@ defmodule Philomena.MixProject do
{:plug_cowboy, "~> 2.0"}, {:plug_cowboy, "~> 2.0"},
{:phoenix_slime, "~> 0.12.0"}, {:phoenix_slime, "~> 0.12.0"},
{:ecto_network, "~> 1.1"}, {:ecto_network, "~> 1.1"},
{:pbkdf2, "~> 2.0"} {:pow, "~> 1.0.11"},
{:bcrypt_elixir, "~> 2.0"}
] ]
end end

View file

@ -1,4 +1,6 @@
%{ %{
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.0.3", "64e0792d5b5064391927bf3b8e436994cafd18ca2d2b76dea5c76e0adcf66b7c", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"comeonin": {:hex, :comeonin, "5.1.2", "fbbbbbfcf0f0e9900c0336d16c8d462edf838ba1759577e29cc5fbd7c28a4540", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"}, "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"},
@ -7,6 +9,7 @@
"ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_network": {:hex, :ecto_network, "1.1.0", "7062004b9324ff13e50c02dab84877f8a55e06db9eabbf2d04bda21da6fc6e8a", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_network": {:hex, :ecto_network, "1.1.0", "7062004b9324ff13e50c02dab84877f8a55e06db9eabbf2d04bda21da6fc6e8a", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"},
"ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
"file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"}, "file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
@ -23,6 +26,7 @@
"plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.15.0", "dd5349161019caeea93efa42f9b22f9d79995c3a86bdffb796427b4c9863b0f0", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "postgrex": {:hex, :postgrex, "0.15.0", "dd5349161019caeea93efa42f9b22f9d79995c3a86bdffb796427b4c9863b0f0", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"pow": {:hex, :pow, "1.0.11", "f5ef721ac17d2bf8f9dd92f5d40fa0b96512d24b91a26603147754034e3a6101", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3.0 or ~> 1.4.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"}, "slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},