This article is part of the confusing world of Authentication in Rails. Feel free to get lost in a gazillion of nearly useless and/or outdated Wikipages.
In application.rb:
class ApplicationController < ActionController::Base
before_filter :authorize
protected
# Override in controller classes that should require authentication
def secure?
false
end
private
def authorize
if secure? && session["person"].nil?
session["return_to"] = request.request_uri
redirect_to :controller => "auth"
return false
end
end
end
#secure? per controllerclass WeblogController < ApplicationController
def index
# show secret stuff
end
protected
def secure?
true
end
end
class SignupController < ApplicationController
def index
# show public stuff
end
def settings
# show secret stuff
end
protected
def secure?
action_name == "settings"
end
end
Multiple protected pages, but not fully protected controllers.
...
protected
def secure?
["onesecretpage", "secondsecretpage"].include?(action_name)
end
...
COMMENT: One small warning here, if I have an action that is not protected, that calls an action that is protected this will not protect the second action. For example if I have something like
...
def index
list
render :action => 'list'
end
def list
#some listing mechanism
end
def add
#some add mechanism
end
def show
#some show mechanism
end
protected
def secure?
["list", "add", "show"].include?(action_name)
end
...
the list action will be called (and displayed) from index since the index action is not protected.
One thing I do is define a class variable regex in my controllers that dictates which methods are available
@@public = /blah|blah/
then my global authentication only requires authentication if action_name =~ @@public
In application.rb:
@@private = // # default to nothing private
protected
def secure?
action_name =~ @@private
end
Then redifine the regexp per controller:
@@private = /user.*$/ # require login for all user* methods
Comment: i love this idea, but it sucks to add this after the fact because you have to rename, actions, rhtml files, and all the links – i wish there was something that combined both.
Sometimes you might want to limit actions based on an arbitrarily defined level, so that you can restrict certain classes of user to certain actions. One way of doing this is:
In application.rb:
# class variable to define the secure levels in:
@@secure = {}
private
def check_auth
# if the secure? routine returns a value greater than 0, the action requires a login
if secure? > 0
if session['id'].nil?
# not authorised yet.
session["returnto"] = request.request_uri
redirect_to :controller => "users" # or wherever your login page is
return false
else
@user = User.find(session['id'])
# check the user's level against the level specified for the action
if @user.level < secure?
render :text => "<p>Action failed due to insufficient user privileges</p>"
end
end
end
end
protected
def secure?
if @@secure.has_key?(action_name)
@@secure[action_name]
else
0
end
end
Then, in the controllers that want protecting:
@@secure = {
'new' => 10,
'create' => 10,
'edit' => 10,
'update' => 10,
'destroy' => 10,
}
See also: LoginGeneratorAccessControlList
Comment: This page was great, and well written, thank you so much.