mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
WIP: Authentication with Guardian/Comeonin
This commit is contained in:
parent
87fa2b9f0f
commit
80e58f765f
114
lib/chess/auth/auth.ex
Normal file
114
lib/chess/auth/auth.ex
Normal file
@ -0,0 +1,114 @@
|
||||
defmodule Chess.Auth do
|
||||
@moduledoc """
|
||||
The Auth context.
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Comeonin.Argon2
|
||||
alias Chess.Repo
|
||||
|
||||
alias Chess.Auth.User
|
||||
|
||||
@doc """
|
||||
Returns the list of users.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_users()
|
||||
[%User{}, ...]
|
||||
|
||||
"""
|
||||
def list_users do
|
||||
Repo.all(User)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single user.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the User does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_user!(123)
|
||||
%User{}
|
||||
|
||||
iex> get_user!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_user!(id), do: Repo.get!(User, id)
|
||||
|
||||
@doc """
|
||||
Creates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_user(%{field: value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> create_user(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_user(attrs \\ %{}) do
|
||||
%User{}
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_user(user, %{field: new_value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> update_user(user, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_user(%User{} = user, attrs) do
|
||||
user
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a User.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_user(user)
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> delete_user(user)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_user(%User{} = user) do
|
||||
Repo.delete(user)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking user changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user(user)
|
||||
%Ecto.Changeset{source: %User{}}
|
||||
|
||||
"""
|
||||
def change_user(%User{} = user) do
|
||||
User.changeset(user, %{})
|
||||
end
|
||||
|
||||
@doc false
|
||||
def authenticate_user(username, password) do
|
||||
Repo.one(
|
||||
from u in User,
|
||||
where: u.username == ^username
|
||||
)
|
||||
|> Argon2.check_pass(password)
|
||||
end
|
||||
end
|
||||
17
lib/chess/auth/guardian.ex
Normal file
17
lib/chess/auth/guardian.ex
Normal file
@ -0,0 +1,17 @@
|
||||
defmodule Chess.Auth.Guardian do
|
||||
use Guardian, otp_app: :auth_ex
|
||||
|
||||
alias Chess.Auth
|
||||
|
||||
def subject_for_token(user, _claims) do
|
||||
{:ok, to_string(user.id)}
|
||||
end
|
||||
|
||||
def resource_from_claims(claims) do
|
||||
user = claims["sub"]
|
||||
|> Auth.get_user!
|
||||
{:ok, user}
|
||||
|
||||
# If something goes wrong here return {:error, reason}
|
||||
end
|
||||
end
|
||||
32
lib/chess/auth/user.ex
Normal file
32
lib/chess/auth/user.ex
Normal file
@ -0,0 +1,32 @@
|
||||
defmodule Chess.Auth.User do
|
||||
@moduledoc false
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Chess.Auth.User
|
||||
alias Comeonin.Argon2
|
||||
|
||||
schema "users" do
|
||||
field :password, :string, virtual: true
|
||||
field :password_hash, :string
|
||||
field :username, :string
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(%User{} = user, attrs) do
|
||||
user
|
||||
|> cast(attrs, [:username, :password])
|
||||
|> validate_required([:username, :password])
|
||||
|> hash_password()
|
||||
end
|
||||
|
||||
defp hash_password(
|
||||
%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset
|
||||
) do
|
||||
change(changeset, Argon2.add_hash(password))
|
||||
end
|
||||
|
||||
defp hash_password(changeset), do: changeset
|
||||
end
|
||||
12
priv/repo/migrations/20180115230143_create_users.exs
Normal file
12
priv/repo/migrations/20180115230143_create_users.exs
Normal file
@ -0,0 +1,12 @@
|
||||
defmodule Chess.Repo.Migrations.CreateUsers do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:users) do
|
||||
add :username, :string
|
||||
add :password_hash, :string
|
||||
|
||||
timestamps()
|
||||
end
|
||||
end
|
||||
end
|
||||
65
test/chess/auth/auth_test.exs
Normal file
65
test/chess/auth/auth_test.exs
Normal file
@ -0,0 +1,65 @@
|
||||
defmodule Chess.AuthTest do
|
||||
use Chess.DataCase
|
||||
|
||||
alias Chess.Auth
|
||||
|
||||
describe "users" do
|
||||
alias Chess.Auth.User
|
||||
|
||||
@valid_attrs %{password: "some password", username: "some username"}
|
||||
@update_attrs %{password: "some updated password", username: "some updated username"}
|
||||
@invalid_attrs %{password: nil, username: nil}
|
||||
|
||||
def user_fixture(attrs \\ %{}) do
|
||||
{:ok, user} =
|
||||
attrs
|
||||
|> Enum.into(@valid_attrs)
|
||||
|> Auth.create_user()
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
test "list_users/0 returns all users" do
|
||||
user = user_fixture()
|
||||
assert Auth.list_users() == [user]
|
||||
end
|
||||
|
||||
test "get_user!/1 returns the user with given id" do
|
||||
user = user_fixture()
|
||||
assert Auth.get_user!(user.id) == user
|
||||
end
|
||||
|
||||
test "create_user/1 with valid data creates a user" do
|
||||
assert {:ok, %User{} = user} = Auth.create_user(@valid_attrs)
|
||||
assert user.username == "some username"
|
||||
end
|
||||
|
||||
test "create_user/1 with invalid data returns error changeset" do
|
||||
assert {:error, %Ecto.Changeset{}} = Auth.create_user(@invalid_attrs)
|
||||
end
|
||||
|
||||
test "update_user/2 with valid data updates the user" do
|
||||
user = user_fixture()
|
||||
assert {:ok, user} = Auth.update_user(user, @update_attrs)
|
||||
assert %User{} = user
|
||||
assert user.username == "some updated username"
|
||||
end
|
||||
|
||||
test "update_user/2 with invalid data returns error changeset" do
|
||||
user = user_fixture()
|
||||
assert {:error, %Ecto.Changeset{}} = Auth.update_user(user, @invalid_attrs)
|
||||
assert user == Auth.get_user!(user.id)
|
||||
end
|
||||
|
||||
test "delete_user/1 deletes the user" do
|
||||
user = user_fixture()
|
||||
assert {:ok, %User{}} = Auth.delete_user(user)
|
||||
assert_raise Ecto.NoResultsError, fn -> Auth.get_user!(user.id) end
|
||||
end
|
||||
|
||||
test "change_user/1 returns a user changeset" do
|
||||
user = user_fixture()
|
||||
assert %Ecto.Changeset{} = Auth.change_user(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user