Last active
April 12, 2018 10:59
-
-
Save mihai-ciupina/3800f5d927fcbf822d653f80e16eb8e6 to your computer and use it in GitHub Desktop.
guardian authentication and authorization https://stackoverflow.solutions/question/show_question_details/558
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Auth do | |
import Comeonin.Bcrypt, only: [checkpw: 2, dummy_checkpw: 0] | |
alias MyApp.Accounts.User | |
alias MyApp.Repo | |
def login(conn, user) do | |
conn | |
|> Guardian.Plug.sign_in(user) | |
end | |
def login_by_email_and_pass(conn, email, given_pass) do | |
user = Repo.get_by(User, email: email) | |
cond do | |
user && checkpw(given_pass, user.password_hash) -> | |
{:ok, login(conn, user)} | |
user -> | |
{:error, :unauthorized, conn} | |
true -> | |
dummy_checkpw | |
{:error, :not_found, conn} | |
end | |
end | |
def logout(conn) do | |
Guardian.Plug.sign_out(conn) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.GuardianErrorHandler do | |
import MyWeb.Router.Helpers | |
def unauthenticated(conn, _params) do | |
conn | |
|> Phoenix.Controller.put_flash(:error, "You must be signed in to access that page.") | |
|> Phoenix.Controller.redirect(to: session_path(conn, :new)) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Guardian configuration | |
config :guardian, Guardian, | |
issuer: "MyApp.#{Mix.env}", | |
ttl: {30, :days}, | |
verify_issuer: true, | |
serializer: MyApp.GuardianSerializer, | |
secret_key: to_string(Mix.env) <> "SuPerseCret_aBraCadabrA_bis" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Accounts.User do | |
use Ecto.Schema | |
import Ecto.Changeset | |
alias MyApp.Accounts.User | |
schema "users" do | |
field :email, :string | |
field :name, :string | |
field :role, :string | |
field :password, :string, virtual: true | |
field :password_hash, :string | |
timestamps() | |
end | |
@doc false | |
def changeset(%User{} = user, attrs) do | |
user | |
|> cast(attrs, [:email, :name, :password_hash, :role]) | |
|> validate_required([:email, :name, :password_hash, :role]) | |
|> unique_constraint(:email) | |
end | |
def update_changeset(%User{} = user, attrs) do | |
user | |
|> changeset(attrs) | |
|> validate_length(:password, min: 6, max: 100) | |
|> validate_confirmation(:password, message: "passwords do not match") | |
|> validate_format(:email, ~r/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/) | |
|> hash_password | |
end | |
def registration_changeset(%User{} = user, attrs) do | |
user | |
|> changeset(attrs) | |
|> validate_required(~w(password)a) | |
|> validate_length(:password, min: 6, max: 100) | |
|> validate_confirmation(:password, message: "passwords do not match", required: true) | |
|> validate_format(:email, ~r/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/) | |
|> hash_password | |
end | |
defp hash_password(changeset) do | |
case changeset do | |
%Ecto.Changeset{valid?: true, changes: %{password: password}} -> | |
put_change(changeset, :password_hash, Comeonin.Bcrypt.hashpwsalt(password)) | |
_ -> | |
changeset | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.CurrentUser do | |
import Plug.Conn | |
import Guardian.Plug | |
def init(opts), do: opts | |
def call(conn, _opts) do | |
current_user = current_resource(conn) | |
assign(conn, :current_user, current_user) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.GuardianSerializer do | |
@behaviour Guardian.Serializer | |
alias MyApp.Repo | |
alias MyApp.Accounts.User | |
def for_token(user = %User{}), do: {:ok, "User:#{user.id}"} | |
def for_token(_), do: {:error, "Unknown resource type"} | |
def from_token("User:" <> id), do: {:ok, Repo.get(User, id)} | |
def from_token(_), do: {:error, "Unknown resource type"} | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyAppWeb.SessionController do | |
use MyAppWeb, :controller | |
import Guardian.Plug | |
plug :scrub_params, "session" when action in ~w(create)a | |
def new(conn, _) do | |
current_user = current_resource(conn) | |
unless current_user do | |
render conn, "new.html" | |
else | |
conn |> redirect(to: page_path(conn, :index)) | |
end | |
end | |
def create(conn, %{"session" => %{"email" => email, "password" => password}}) do | |
case MyApp.Auth.login_by_email_and_pass(conn, email, password) do | |
{:ok, conn} -> | |
conn | |
|> put_flash(:info, "You are signed in!") | |
|> redirect(to: page_path(conn, :index)) | |
{:error, reason, conn} -> | |
conn | |
|> put_flash(:error, reason) | |
|> render("new.html") | |
end | |
end | |
def delete(conn, _) do | |
conn | |
|> MyApp.Auth.logout | |
|> put_flash(:info, "You signed out!") | |
|> redirect(to: page_path(conn, :index)) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyAppWeb.UserController do | |
use MyAppWeb, :controller | |
alias MyApp.Accounts | |
alias MyApp.Accounts.User | |
def index(conn, _params) do | |
users = Accounts.list_users() | |
render(conn, "index.html", users: users) | |
end | |
def new(conn, _params) do | |
changeset = Accounts.change_user(%User{}) | |
render(conn, "new.html", changeset: changeset) | |
end | |
def create(conn, %{"user" => user_params}) do | |
case Accounts.create_user(user_params) do | |
{:ok, user} -> | |
conn | |
|> put_flash(:info, "User created successfully.") | |
|> redirect(to: session_path(conn, :new)) | |
{:error, %Ecto.Changeset{} = changeset} -> | |
render(conn, "new.html", changeset: changeset) | |
end | |
end | |
def show(conn, %{"id" => id}) do | |
user = Accounts.get_user!(id) | |
render(conn, "show.html", user: user) | |
end | |
def edit(conn, %{"id" => id}) do | |
user = Accounts.get_user!(id) | |
changeset = Accounts.change_user(user) | |
render(conn, "edit.html", user: user, changeset: changeset) | |
end | |
def update(conn, %{"id" => id, "user" => user_params}) do | |
user = Accounts.get_user!(id) | |
case Accounts.update_user(user, user_params) do | |
{:ok, user} -> | |
conn | |
|> put_flash(:info, "User updated successfully.") | |
|> redirect(to: user_path(conn, :show, user)) | |
{:error, %Ecto.Changeset{} = changeset} -> | |
render(conn, "edit.html", user: user, changeset: changeset) | |
end | |
end | |
def delete(conn, %{"id" => id}) do | |
user = Accounts.get_user!(id) | |
{:ok, _user} = Accounts.delete_user(user) | |
conn | |
|> put_flash(:info, "User deleted successfully.") | |
|> redirect(to: user_path(conn, :index)) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.. | |
pipeline :with_session do | |
plug Guardian.Plug.VerifySession | |
plug Guardian.Plug.LoadResource | |
plug MyApp.CurrentUser | |
end | |
.. | |
pipeline :login_required do | |
plug Guardian.Plug.EnsureAuthenticated, handler: MyApp.GuardianErrorHandler | |
end | |
.. | |
scope "/", MyAppWeb do | |
pipe_through [:browser, :with_session] # Use the default browser stack | |
.. | |
resources "/users", UserController, only: [:new, :create] | |
# registered user zone | |
scope "/" do | |
pipe_through [:login_required] | |
resources "/users", UserController, only: [:edit, :show, :update] | |
end | |
end | |
.. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%= if @current_user do %> | |
<li><%= @current_user.email %> (<%= @current_user.id %>)</li> | |
<li> | |
<%= link "Sign out", to: session_path(@conn, :delete, | |
@current_user), | |
method: "delete" %> | |
</li> | |
<% else %> | |
<li><%= link "Register", to: user_path(@conn, :new) %></li> | |
<li><%= link "Sign in", to: session_path(@conn, :new) %></li> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%= render "_header.html", conn: @conn, current_user: @current_user %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="content-wrapper" style="min-height: 916px;"> | |
<div class="content"> | |
<h1>Sign in</h1> | |
<%= form_for @conn, session_path(@conn, :create), [as: :session], fn f -> %> | |
<div class="form-group"> | |
<%= text_input f, :email, placeholder: "Email", class: "form-control", type: "email" %> | |
</div> | |
<div class="form-group"> | |
<%= password_input f, :password, placeholder: "Password", class: "form-control" %> | |
</div> | |
<%= submit "Sign in", class: "btn btn-primary" %> | |
<% end %> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%= form_for @changeset, @action, fn f -> %> | |
<%= if @changeset.action do %> | |
<div class="alert alert-danger"> | |
<p>Oops, something went wrong! Please check the errors below.</p> | |
</div> | |
<% end %> | |
<div class="form-group"> | |
<%= label f, :name, class: "control-label" %> | |
<%= text_input f, :name, class: "form-control" %> | |
<%= error_tag f, :name %> | |
</div> | |
<div class="form-group"> | |
<%= label f, :email, class: "control-label" %> | |
<%= email_input f, :email, class: "form-control" %> | |
<%= error_tag f, :email %> | |
</div> | |
<div class="form-group"> | |
<%= label f, :password, class: "control-label" %> | |
<%= password_input f, :password, placeholder: "Password", class: "form-control" %> | |
<%= error_tag f, :password %> | |
</div> | |
<div class="form-group"> | |
<%= label f, :password_confirmation, class: "control-label" %> | |
<%= password_input f, :password_confirmation, placeholder: "Password confirmation", class: "form-control" %> | |
<%= error_tag f, :password_confirmation %> | |
</div> | |
<div class="form-group"> | |
<%= submit "Submit", class: "btn btn-primary" %> | |
</div> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyAppWeb.SessionView do | |
use MyAppWeb, :view | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defp deps do | |
[ | |
.. | |
{:comeonin, "~> 2.5"}, | |
{:guardian, "~> 0.12.0"}, | |
.. | |
] | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# lib/my_app_web/router.ex | |
.. | |
pipeline :with_session do | |
plug Guardian.Plug.VerifySession | |
plug Guardian.Plug.LoadResource | |
plug MyApp.CurrentUser | |
end | |
.. | |
pipeline :login_required do | |
plug Guardian.Plug.EnsureAuthenticated, handler: MyApp.GuardianErrorHandler | |
end | |
.. | |
scope "/", MyAppWeb do | |
pipe_through [:browser, :with_session] # Use the default browser stack | |
.. | |
resources "/users", UserController, only: [:new, :create] | |
# registered user zone | |
scope "/" do | |
pipe_through [:login_required] | |
resources "/users", UserController, only: [:edit, :show, :update] | |
end | |
end | |
.. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Repo.Migrations.CreateMyApp.Accounts.User do | |
use Ecto.Migration | |
def change do | |
create table(:users) do | |
add :name, :string, null: false | |
add :email, :string, null: false | |
add :role, :string, null: false | |
add :password_hash, :string | |
timestamps() | |
end | |
create unique_index(:users, [:email]) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment