Building our create session function

Create is going to be a little trickier to write, but not by too much. One of the first gotchas is that we'll need to update the accounts context to look a user up by their username. Hop over to the accounts context (lib/vocial/accounts/accounts.ex) and add the following function:

  def get_user_by_username(username) do
Repo.get_by(User, username: username)
end

In the case where we don't get any users back, we'll return a nil value, but otherwise we'll assume that we got back a user that we can use to check the encrypted password of! get_by2 just takes the query (in our case, just any user schema) and the conditions to check by and attempts to return back the appropriate row from the table specified in the query.

Returning back over to our controller, we'll write the code to look for a user, a dummy function call to check that the user's password matches, and the session-setting logic. First, add an alias to Vocial.Accounts at the top:

Then, we'll build the create action:

  def create(conn, %{"username" => username, "password" => password}) do
with user <- Accounts.get_user_by_username(username),
{:ok, login_user} <- login(user, password)
do
conn
|> put_flash(:info, "Logged in successfully!")
|> put_session(:user, %{ id: login_user.id, username: login_user.username, email: login_user.email })
|> redirect(to: "/")
else
{:error, _} ->
conn
|> put_flash(:error, "Invalid username/password!")
|> render("new.html")
end
end

defp login(user, password) do
true
end

If you go back to the login page by visiting http://localhost:4000/login and type in a username for a user that exists in your system and any password, you should get a successful login message! This is great, but let's make it a tiny bit more secure by ACTUALLY checking the password using Comeonin. Again, good news: this is a really simple thing to do, thanks to the Comeonin developers:

  defp login(user, password) do
Comeonin.Bcrypt.check_pass(user, password)
end

check_pass/2 verifies that the supplied struct or map has either an encrypted_password key or a password_hash key, and then verifies that encrypted value against the plaintext password that the user supplied by encrypting the plaintext password and comparing the two. In the case that a nil is passed along as the first argument of check_pass, it will simulate checking a password so that timing can't be used to verify if a username is valid or not! Now return back to your login form, try to log in with the right username/password, verify the results, and then try again with the wrong information! Everything should be working exactly as expected! You have now successfully implemented a user login and session system!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset