Devise: http://github.com/plataformate/devise
Slides: http://presentations.royvandewater.com/?file=devise.html
Project on Github: http://github.com/royvandewater/devise-samples
rails g devise:install
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
root :to => "static#index"
<%= notice %>
<%= alert %>
rails g devise user
<% unless user_signed_in? -%>
before_filter :authenticate_user!
To require email confirmation, uncomment the following lines from the devise migration:
# Rails.root/db/migrations/2011011620391_devise_create_users.rb
def self.up
create_table(:users) do |t|
t.confirmable
end
add_index :users, :confirmation_token, :unique => true
end
And add ":confirmable" to the devise line in your user model:
# Rails.root/app/models/user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
Then rerun your migrations and you're done
Note: The development server must be restarted to recognize "user_confirmation_url" as a valid path
By default, devise uses its own views, located inside the gem.
To use custom sign in and new user registration forms run the following devise generator:
rails g devise:views
This pulls in all devise views, allowing them to be changed.
Note: You can overwrite only the views you want to update. Missing views will automatically be retrieved from the gem
To execute custom code on login/logout, override the sessions controller:
# Rails.root/app/controllers/sessions.rb
class SessionsController < Devise::SessionsController
def create
logger.info "Attempt to sign in by #{ params[:user][:email] }"
super
end
def destroy
logger.info "#{ current_user.email } signed out"
super
end
end
And point the devise routes line at your new controller:
# Rails.root/config/routes.rb
devise_for :users, :controllers => { :sessions => :sessions }
The views for the overwritten controller must be copied locally into apps/views/sessions
Create your own custom encryptor in the lib directory of the rails app:
# Rails.root/lib/devise/encryptors/rot13.rb
module Devise
module Encryptors
class Rot13 < Base
def self.digest(password, stretches, salt, pepper)
"#{password}-#{salt}".tr! "A-Za-z", "N-ZA-Mn-za-m"
end
end
end
end
Then require and select your new encryptor in the Devise initializer
# Rails.root/config/initializers/devise.rb
require "devise/encryptors/rot13"
Devise.setup do |config|
config.encryptor = :rot13
end
To enable token authentication uncomment the following lines from the devise migration:
# Rails.root/db/migrations/2011011620391_devise_create_users.rb
def self.up
create_table(:users) do |t|
t.token_authenticatable
end
end
And add ":token_authenticatable" to the devise line in your user model:
# Rails.root/app/models/user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:token_authenticatable
The authentication token can be generated using
@user.reset_authentication_token!
The user can now authenticate himself like this:
http://localhost:3000/?auth_token=OyZSe8ozy_os5acibqNC
or by passing the auth_token as the username in HTTP Basic Auth
Authentication tokens are permanent by default
To create a single access token, clear or reset it on token login
Devise adds the instance method after_token_authentication to the user model and calls it after every successful token login
To clear the authentication token, add the following to the user model:
def after_token_authentication
update_attributes :authentication_token => nil
end
To reset the authentication, use the built in token reset method:
def after_token_authentication
reset_authentication_token!
end
Devise disables basic auth by default
To enable, uncomment the following line from config/initializers/devise.rb and set its value to true (and restart the server):
config.http_authenticatable = true
To test if devise is now accepting HTTP Basic Auth, try the following curl statement:
curl -u user@example.com:password http://localhost:3000/users
Add a boolean to the user model
class AddIsAdminToUsers < ActiveRecord::Migration
def self.up
add_column :users, :is_admin, :boolean
end
And add a before filter to whatever actions require admin access
# In controller
before_filter :require_admin!, :except => [:index, :show]
# In application controller
protected
def require_admin!
unless current_user.try :is_admin?
redirect_to root_path, :alert => "Access Denied"
end
end
Note: For more complex permissions, including permit and restriction functionality, take a look at cream
Run the devise generator for your second user type
rails g devise employee
The employee user now has his own login path, found at new_employee_session_path
Additionaly helpers include employee_signed_id?, current_employee and the authenticate_employee! before filter
Actions that need to allow either user type can use the following before filter:
# In the controller
before_filter :require_user_or_employee!
# In the application controller
protected
def require_user_or_employee!
unless user_signed_in? or employee_signed_in?
redirect_to root_path, :alert => "Access Denied"
end
end
Add the username attribute to the user model:
rails g add_username_to_users username:string
Override the find_for_database_authentication method in the user controller:
protected
def self.find_for_database_authentication(conditions)
login = conditions.delete(:login)
where(conditions)
.where(["username = :login OR email = :login",
{:login => login}])
.first
end
Uncomment the config.authentication_keys line in the devise initializers and replace :email with :login
config.authentication_keys = [ :login ]
Add the login as an attr_accessor on the user model
attr_accessor :login
Update the registration and login view (remember to run the devise:views generator)
# app/views/devise/sessions/new.html.erb
<%= f.label :login %>
<%= f.text_field :login %>
# app/views/devise/registrations/new.html.erb
<%= f.label :username %>
<%= f.text_field :username %>
Add a login form that posts to the user_sessions_path
<%= form_for(:user, :url => user_session_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in" %>
<% end %>
Devise: http://github.com/plataformate/devise
Slides: http://presentations.royvandewater.com/?file=devise.html
Project on Github: http://github.com/royvandewater/devise-samples