#385 Authorization from Scratch Part 1 pro
Oct 07, 2012 | 15 minutes | Security, Authorization
Authorization can be difficult to implement and test because it often involves complex logic that exists throughout the entire app. Here I demonstrate how to test and implement authorization from scratch.
- Download:
- source codeProject Files in Zip (70.1 KB)
- mp4Full Size H.264 Video (38.1 MB)
- m4vSmaller H.264 Video (18.9 MB)
- webmFull Size VP8 Video (21.6 MB)
- ogvFull Size Theora Video (43.1 MB)
Resources
application_controller.rb
before_filter :authorize delegate :allow?, to: :current_permission helper_method :allow? private def current_permission @current_permission ||= Permission.new(current_user) end def authorize if !current_permission.allow?(params[:controller], params[:action]) redirect_to root_url, alert: "Not authorized." end end
models/permission.rb
class Permission < Struct.new(:user) def allow?(controller, action) return true if controller == "sessions" return true if controller == "users" && action.in?(%w[new create]) return true if controller == "topics" && action.in?(%w[index show]) if user return true if controller == "users" && action.in?(%w[edit update]) return true if controller == "topics" && action != "destroy" return true if user.admin? end false end end
spec/spec_helper.rb
config.filter_run focus: true config.run_all_when_everything_filtered = true
spec/models/permission_spec.rb
require "spec_helper" RSpec::Matchers.define :allow do |*args| match do |permission| permission.allow?(*args).should be_true end end describe Permission do describe "as guest" do subject { Permission.new(nil) } it { should allow("topics", "index") } it { should allow("topics", "show") } it { should_not allow("topics", "new") } it { should_not allow("topics", "create") } it { should_not allow("topics", "edit") } it { should_not allow("topics", "update") } it { should_not allow("topics", "destroy") } it { should allow("sessions", "new") } it { should allow("sessions", "create") } it { should allow("sessions", "destroy") } it { should allow("users", "new") } it { should allow("users", "create") } it { should_not allow("users", "edit") } it { should_not allow("users", "update") } end describe "as admin" do subject { Permission.new(build(:user, admin: true)) } it { should allow("anything", "here") } end describe "as member" do subject { Permission.new(build(:user, admin: false)) } it { should allow("topics", "index") } it { should allow("topics", "show") } it { should allow("topics", "new") } it { should allow("topics", "create") } it { should allow("topics", "edit") } it { should allow("topics", "update") } it { should_not allow("topics", "destroy") } it { should allow("sessions", "new") } it { should allow("sessions", "create") } it { should allow("sessions", "destroy") } it { should allow("users", "new") } it { should allow("users", "create") } it { should allow("users", "edit") } it { should allow("users", "update") } end end
spec/requests/topics_spec.rb
it "cannot edit topic as guest" do topic = create(:topic) visit edit_topic_path(topic) page.should have_content("Not authorized") end