Perm
Incredibly simple permission management i.e. authorization.
Quickstart
gem install perm
Setup
Let's create a simple example with users & posts.
class User
attr_reader :roles, :posts
def initialize(roles: [])
@roles = roles
@posts = []
end
end
class Post
attr_reader :user, :title
attr_accessor :published
def initialize(user:, title:)
@user = user
@title = title
@user.posts << self
end
end
Once our basic classes have be defined, we can create an authorized user to manage permissions.
class AuthorizedUser < Perm::Authorized
def can_read?(post)
return true if user.roles.include?(:admin)
return true if user.roles.include?(:editor)
return true if user == post.user
post.published
end
def can_update?(post)
return true if user.roles.include?(:admin)
return true if user.roles.include?(:editor)
user == post.user
end
def can_delete?(post)
return true if user.roles.include?(:admin)
user == post.user
end
end
Authorized users do the following.
- wrap user objects — somewhat like the presenter pattern
- add behavior to wrapped users
- respond to authorization methods defined as
can_OPERATION?
- secure by default i.e. authorization checks return false until implemented
Usage
Create some users
mary = User.new(roles: [:admin])
john = User.new(roles: [:editor, :writer])
beth = User.new(roles: [:writer])
drew = User.new
Create a post
post = Post.new(user: beth, title: "Authorization made easy")
Wrap each user with an authorizer
authorized_mary = AuthorizedUser.new(mary)
authorized_john = AuthorizedUser.new(john)
authorized_beth = AuthorizedUser.new(beth)
authorized_drew = AuthorizedUser.new(drew)
# wrapped users continue to act like users
authorized_beth.posts # => [#<Post:0x007fe35d081798 @title="Authorization made easy"...
# if conflicts arise, simply access the original
authorized_beth.user
Check permissions
authorized_mary.can_read?(post) # => true
authorized_mary.can_update?(post) # => true
authorized_mary.can_delete?(post) # => true
authorized_john.can_read?(post) # => true
authorized_john.can_update?(post) # => true
authorized_john.can_delete?(post) # => false
authorized_beth.can_read?(post) # => true
authorized_beth.can_update?(post) # => true
authorized_beth.can_delete?(post) # => true
authorized_drew.can_read?(post) # => false
authorized_drew.can_update?(post) # => false
authorized_drew.can_delete?(post) # => false
post.published = true
authorized_drew.can_read?(post) # => true
# we can also check unimplemented permissions
authorized_mary.can_create?(post) # => false
authorized_john.can_view?(post) # => false