I'm trying to build a very simple login page with username and password authentication using BCrypt.
There are two features, the first is to create a username and password, and the second is authenticate using login page. (create a new user, login with that user)
Below is the controller and User model code for creating a username and password. View model is not included, but it includes a simple form asking the user to create a username, password and confirm password
Controller:
get '/new_user' do
erb :new_user
end
post '/new_user' do
if @password == @password_confirm
new_user = User.new(username: params[:username])
new_user.password = params[:password]
new_user.insert_user
redirect '/index'
else
redirect '/new_user'
end
end
Model:
def initialize(params = {})
@username = params.fetch(:username, "test")
@password = params.fetch(:password, "test")
end
def password=(new_password)
@password = BCrypt::Password.create(new_password)
@db_password = BCrypt::Password.new(@password)
end
def insert_user
db = SQLite3::Database.open("helper_database")
db_results_as_hash = true
db.execute("INSERT INTO users (username, password) VALUES (?,?)", [@username, @db_password])
end
In the above, a new instance is created to pass username and password. If password and confirm password match, the password method will create an encrypted password, and the insert method will insert username and the encrypted password into the database using simple SQL command.
After the username and encrypted password have been inserted into the database. I want to use the login page to validate. I create a new User instance, passing the username and password params to the authentication method shown below. The method will look up the password corresponding the params username and evaluate the params password against the encrypted password.
Below is the controller and User model for Login
Controller:
get '/login' do
erb :login
end
post '/login' do
@user = User.new(username: params[:username], password: params[:password])
if @user.authenticate()
redirect '/index'
else
erb :login
end
end
Model:
def authenticate
db = SQLite3::Database.open("helper_database")
db.results_as_hash = true
password = db.execute("SELECT password FROM users WHERE username = '#{@username}'")
password = password[0]["password"]
password = BCrypt::Password.new(password)
@password == password
end
Above, I'm attempting to retrieve the encrypted password (string format) from SQL, convert to a Bcrypt object and validate the password against it. Theoretically, the method should return true assuming the entered password is correct, but it returns false.
What might the issue be?
You don’t appear to be hashing the incoming password when you authenticate. This is because you’re doing @password == password
where @password
is the plain-text String
password (from User#initialize
from post '/login'
).
You should flip the comparison so it uses BCrypt::Password#==
: password == @password
.