Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 163 lines (108 sloc) 5.108 kb
714cffe Stephen Bannasch initial import of rails plugin: simple_access_control
stepheneb authored
1 SimpleAccessControl
2 ===================
3
4 Acknowledgements: I give all credit to Ezra and Technoweenie for their two plugins which
5 inspired the interface design and a lot of the code for this one.
6
7 SimpleAccessControl is a streamlined, intuitive authorisation system. It derives heavily from
8 acl_system2 and has made clear some problems which plagued me when first using it. Some
9 fixes to acl_system2's design:
10
11 * a normal Rails syntax:
12 access_rule 'admin', :only => :index
13 access_rule '(moderator || admin)', :only => :new
14 * error handling for helper methods (permit? bombed when current_user == nil)
15 * one-line parser, easy to replace or alter
16 * proper before_filter usage, meaning access rules are parsed only when needed
17 * no overrideable default (which I found counter-intuitive in the end)
18
19 Also, it has two methods, access_control and permit?, for those moving from acl_system2.
20
21 But, let me stress, everyone likes a slightly different system, so this one may not be
22 your style. I find it synchronises very well with the interface of Acts as Authenticated (even
23 though I have modified it so much that it's now called Authenticated Cookie).
24
25 INSTALLATION
26 ============
27
28 Create the following migration:
29
30 create_table "roles", :force => true do |t|
31 t.column "title", :string
32 end
33 create_table "roles_users", :id => false, :force => true do |t|
34 t.column "role_id", :integer
35 t.column "user_id", :integer
36 end
37
38 In your User model, you must have:
39
40 has_and_belongs_to_many :roles
31e702e Use shoulda for non-existant tests. Add jeweler requirement in Rakefile....
Nathan Hyde authored
41
714cffe Stephen Bannasch initial import of rails plugin: simple_access_control
stepheneb authored
42 In your Roles model, you must have:
43
44 has_and_belongs_to_many :users
45
46 Your controllers must have the following two methods or variants of them:
47
48 # Returns a User object
49 def current_user
50 @current_user
51 end
52
53 # Returns true or false if a User object exists for this session
54 def logged_in?
55 @current_user.is_a? User
56 end
57
58
59 SPECIAL NEEDS
60 =============
61
62 If you want to permit anonymous users without demanding that they are logged in, first you
63 must ensure that logged_in? returns true in all cases, otherwise permission will be denied.
64 The following approach should work:
65
66 1. Create the 'guest' and 'user' roles, e.g.:
67
68 guest = Role.create(:title => 'guest')
69 user = Role.create(:title => 'user')
70
71 2. In your registration/user creation area, ensure all real users have the 'user' role, e.g.:
72
73 @user = User.create(params[:user])
74 unless @user.roles.any? { |r| r.title == 'user' }
75 @user.roles << Role.find_by_title('user')
76 end
31e702e Use shoulda for non-existant tests. Add jeweler requirement in Rakefile....
Nathan Hyde authored
77 @user.save
714cffe Stephen Bannasch initial import of rails plugin: simple_access_control
stepheneb authored
78
79 [At this point you have two options: a real or virtual anonymous account]
80
81 First Approach: Real Anonymous User
82
83 3a. Create an anonymous user, e.g.:
84
85 @anonymous = User.create(:login => 'anonymous', :password => '*', :activated => true)
86
87 4a. Add the role to the Anonymous user (in a migration or in script/console), e.g.:
88
89 anonymous.roles << Role.find_by_title('guest')
90 anonymous.save
91
92 5a. In your ApplicationController, set unauthenticated users as 'anonymous', e.g.:
93
94 before_filter :default_to_guest
95
96 def default_to_guest
97 self.current_user = User.find_by_login('anonymous', :include => :roles) unless logged_in?
98 end
99
100
101 Second Approach: Virtual Anonymous User
102
103 3a. In your ApplicationController, create a virtual anonymous account if unauthenticated:
104
105 before_filter :default_to_virtual_guest
106 def default_to_virtual_guest
107 self.current_user = self.anonymous_user unless logged_in?
108 end
109
110 def anonymous_user
111 anonymous = User.new(:login => 'anonymous', :name => 'Guest')
112 anonymous.roles << Role.new(:title => 'guest')
113 anonymous.readonly!
114 anonymous
115 end
116
117
118 USAGE
119 =====
120
121 The plugin is automatically hooked into ActionController::Base.
122
123 In your controllers, add access rules like so:
124
125 access_rule 'admin', :only => :destroy
126 access_rule 'user || admin', :only => [:new, :create, :edit, :update]
127
128 Note the use of Ruby-style operators. These strings are real conditionals and should be treated as
129 such. Every grouping of non-operator characters will be considered a role title.
130
131 In your views, you can use the following:
132
133 <% restrict_to 'admin || moderator' do %>
134 <%= link_to "Admin Area", admin_area_url %>
135 <% end %>
31e702e Use shoulda for non-existant tests. Add jeweler requirement in Rakefile....
Nathan Hyde authored
136
714cffe Stephen Bannasch initial import of rails plugin: simple_access_control
stepheneb authored
137 AND
138
139 <%= link_to("Admin Area", admin_area_url) if has_permission?('admin || moderator') %>
140
141 There are also transitional methods which help you move from acl_system2 to this plugin -- I do this
142 not to denegrate acl_system2 but because I did this for myself and decided to include it. The two
143 systems are rather similar.
144
145 Also, there are two callbacks, permission_granted and permission_denied, which may define in your
146 controllers to customise their response. For example:
147
148 def permission_granted
149 logger.info("[authentication] Permission granted to %s at %s for %s" %
150 [(logged_in? ? current_user.login : 'guest'), Time.now, request.request_uri])
151 end
31e702e Use shoulda for non-existant tests. Add jeweler requirement in Rakefile....
Nathan Hyde authored
152
714cffe Stephen Bannasch initial import of rails plugin: simple_access_control
stepheneb authored
153 def permission_denied
154 logger.info("[authentication] Permission denied to %s at %s for %s" %
155 [(logged_in? ? current_user.login : 'guest'), Time.now, request.request_uri])
156 end
157
158
159 That's it!
160
161
162 VARIATION BY MABS29
Something went wrong with that request. Please try again.