Tachiban (立ち番 - standing watch) provides simple authentication system for Hanami web applications by using bcrypt for password hashing and offers the following functionalities (with methods listed below under Methods by features):
- Session handling
- Password reset
The Tachiban logic (apart from the Authorization) and code were extracted from a Hanami based web app using Hanami::Model and was also used in a Camping based web app using Active Record.
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
$ gem install tachiban
Tachiban is already setup to be included by your Hanami application:
::::Controller.configure do prepare do include :: end end
Prior to logging in or authenticating the user, retrieve the entity from the
database and assign it to the instance variable of
The password reset methods require the user entity to have the following attributes:
token and password_reset_sent_at (set as
Time.now). The token can be used to compose
the password reset url and to later retrieve the correct user from
the database when the user visits the password reset url.
The password_reset_sent_at can be used to check the reset link validity.
The only prerequisite for the authorization is the attribute of role for the user entity.
The entity for which authentication is used must have the
hashed_pass to hold the generated hashed password.
To create a user with a hashed password use the
method for the password and store it as the user's attribute
# Create action for an entity def call(params) password = params[:newuser][:password] hashed_pass = hashed_password(password) repository = UserRepository.new @user = repository.create(name: name, surname: surname, email: email, hashed_pass: hashed_pass)) end
To authenticate a user use the
authenticated?(input_password) method and log
them in with the
login method. Authentication is successful if the user exists and passwords match.
The user is logged in by setting the user object as the
After the user is logged in the session start time is defined as
session[:session_start_time] = Time.now. A flash message is also
flash[:success_notice] = flash_message.
session[:session_start_time] is then used by the
method to determine whether the session has expired or not.
Example of session creation for an entity
# Create action for an entity session email = params[:entity_session][:email] password = params[:entity_session][:password] @user = EntityRepository.new.find_by_email(email) login("You have been successfully logged in.") if authenticated?(password)
To check whether the user is logged in use the
If the user is not logged in the
logout method takes over.
Tachiban handles session expiration by checking if a session has expired and then restarts the session start time if the session is still valid or proceeds with the following if the session has expired:
- setting the
- a flash message is set:
flash[:failed_notice] = "Your session has expired"
- redirects to the
routes.root_pathwhich can be overwritten by assigning a different url to @redirect_url
session_expired? method compares the session start time
increased for the defined
@validity_time (set to 10 minutes
by default, but can be overwritten) with the current time.
def handle_session if session_expired? @redirect_url ||= routes.root_path session[:current_user] = nil flash[:failed_notice] = "Your session has expired" redirect_to @redirect_url else restart_session_counter end end
Example of session handling in a share code module
module Web module HandleSession def self.included(action) action.class_eval do before :handle_session end end end end
The password reset feature provides a few simple methods to generate a token, email subject and body. It is also possible to specify and check the validity of the password reset url.
token # => "YbRucc8YUlFJrYYp04eQKQ"
email_subject(SomeApp) # => "SomeApp -- password reset request"
Provide the base url, the token and the number and type of the time units for the validity of the link.
body = email_body(base_url, url_token, 2, "hour") # => "Visit this url to reset your password: http://localhost:2300/passwordupdate/asdasdasdaerwrw. # The url will be valid for 2 hour(s).")
The link validity must me specified in seconds. The method compares the
current time with the time when the password reset link was sent increased
by the link validity:
Time.now > @user.password_reset_sent_at + link_validity
Authorization support was setup as inspired by this blog post.
Authorization features support the generation of policy files for each controller where authorized roles are specified for each action.
tachiban -n mightyPoster -p post
The above CLI command will generate a policy file for the application mightyPoster (not the project) and the controller post. The file will be generated as
Each application would have its own
The command must be run in the project root folder.
Once the file is generated the authorized roles variables in the initialize block for required actions need to be uncommneted and supplied with specific roles.
Then we can check if a user is authorized:
(controller, role, action)
- Add support for level based authorizations. [x]
- Add generators for adding authorization rules to existing policies.
- Add generators for entities with required attributes.
session[:current_user] is not set as the user object, but as the user object id.
session.clear to remove any other values upon logout.
After checking out the repo, run
bin/setup to install dependencies. Then, run
rake test to run the tests. You can also run
bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run
bundle exec rake install. To release a new version, update the version number in
version.rb, and then run
bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the
.gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/sebastjan-hribar/tachiban. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.