Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 163 lines (108 sloc) 5.108 kB
714cffe @stepheneb 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 Rakefi…
Nathan Hyde authored
41
714cffe @stepheneb 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 Rakefi…
Nathan Hyde authored
77 @user.save
714cffe @stepheneb 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 Rakefi…
Nathan Hyde authored
136
714cffe @stepheneb 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 Rakefi…
Nathan Hyde authored
152
714cffe @stepheneb 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.