If you haven't used the authlogic plugin for authentication, you're possibly missing a trick. It's a great piece of code.
However, it's poorly documented for anything out of the well trodden path. Which is a pity because it's so powerful.
Authlogic makes assumptions about how your login facility will work. In particular, it assumes that you will have a login and a password. Which, for more enterprise applications and larger web services, fall short of the mark. Most larger services need a three-way, not two-way authentication. Typically it is customerID, user ID and password. Meaning that user IDs are not unique across customers. Which makes sense given that for most markets, different clients will have the same usernames (e.g. admin, sales, info, etc).
This means that to use authlogic, you need to extend it to use your additional fields.
The easy way to do this is to extend your UserSession class by adding an accessor. For example, we use a company short name as a company ID, so in our case, it's:
This in turn means that you have to now modify your user_sessions_controller so that you make your logins company-aware:
class UserSessionsController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
protect_from_forgery :except => [:create]
def index
render :action => :new
end
def new
end
def create
@prevCompSname=params[:user_session]["company_sname"] || ""
company=Company.find(:all,:conditions => ["lower(short_name) = lower(?)",@prevCompSname]).first
$companyID=(company&&company.id)||0
if $companyID > 0
@user_session = UserSession.new(params[:user_session])
if @user_session.save
flash[:notice] = "Login successful!"
@user_session.user.reset_persistence_token!
@user_session.save
redirect_to '/mycontroller'
else
flash[:error] = "Login failed!"
redirect_to :action => :show, :controller => :failure_page
end
else
flash[:error] = "Login failed!"
redirect_to :action => :show, :controller => :failure_page
end
end
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
render :action => :new
end
end
Unfortunately, there is an obscure bug in authlogic that means that the persistence sometimes breaks. You end up with an attempt to select from your user table with perishable_token=1 instead of a string, which results in an SQL error and the login failing.
Some people have found work-arounds to this by unpacking the gem. However, a more reliable fix that we found was to simply explicitly call the method to force a persistent token in the User model:
and then to make sure that this persistence token is saved for the sesssion, you have to call the session save:
This then gives you a persistence token that is saved across the sessions as it should be.
However, it's poorly documented for anything out of the well trodden path. Which is a pity because it's so powerful.
Authlogic makes assumptions about how your login facility will work. In particular, it assumes that you will have a login and a password. Which, for more enterprise applications and larger web services, fall short of the mark. Most larger services need a three-way, not two-way authentication. Typically it is customerID, user ID and password. Meaning that user IDs are not unique across customers. Which makes sense given that for most markets, different clients will have the same usernames (e.g. admin, sales, info, etc).
This means that to use authlogic, you need to extend it to use your additional fields.
The easy way to do this is to extend your UserSession class by adding an accessor. For example, we use a company short name as a company ID, so in our case, it's:
class UserSession < Authlogic::Session::Base
attr_accessor :company_sname # Adds company ID to the default Authlogic session fields because this isn't there in standard Authlogic
end
attr_accessor :company_sname # Adds company ID to the default Authlogic session fields because this isn't there in standard Authlogic
end
class UserSessionsController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
protect_from_forgery :except => [:create]
def index
render :action => :new
end
def new
end
def create
@prevCompSname=params[:user_session]["company_sname"] || ""
company=Company.find(:all,:conditions => ["lower(short_name) = lower(?)",@prevCompSname]).first
$companyID=(company&&company.id)||0
if $companyID > 0
@user_session = UserSession.new(params[:user_session])
if @user_session.save
flash[:notice] = "Login successful!"
@user_session.user.reset_persistence_token!
@user_session.save
redirect_to '/mycontroller'
else
flash[:error] = "Login failed!"
redirect_to :action => :show, :controller => :failure_page
end
else
flash[:error] = "Login failed!"
redirect_to :action => :show, :controller => :failure_page
end
end
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
render :action => :new
end
end
Unfortunately, there is an obscure bug in authlogic that means that the persistence sometimes breaks. You end up with an attempt to select from your user table with perishable_token=1 instead of a string, which results in an SQL error and the login failing.
Some people have found work-arounds to this by unpacking the gem. However, a more reliable fix that we found was to simply explicitly call the method to force a persistent token in the User model:
@user_session.user.reset_persistence_token!
and then to make sure that this persistence token is saved for the sesssion, you have to call the session save:
@user_session.save
This then gives you a persistence token that is saved across the sessions as it should be.