1
0
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:
Daniel Barber 2018-01-15 21:29:28 -05:00
parent 87fa2b9f0f
commit 80e58f765f
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
5 changed files with 240 additions and 0 deletions

114
lib/chess/auth/auth.ex Normal file
View 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

View 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
View 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

View 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

View 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