davydovanton / kan

Simple, functional authorization library and role management for ruby
http://www.kanrb.org
MIT License
232 stars 12 forks source link

Proposal: Role system #3

Closed davydovanton closed 6 years ago

davydovanton commented 6 years ago

Thanks, @apotonick for really good question:

https://twitter.com/apotonick/status/951359565198778368

I think we can define "role" for each abilities class and after that use it for detect right abilities for scope. For example:

module Post
  class AnonymousAbilities
    include Kan::Abilities

    role :anonymous do |user, _|
      user.id.nil?
    end

    register(:read) { |_, _| true }
    register(:edit, :delete) { |user, post| false }
  end

  class BaseAbilities
    include Kan::Abilities

    role :all do |_, _|
      true
    end

    register(:read) { |_, _| true }
    register(:edit, :delete) { |user, post| false }
  end

  class AuthorAbilities
    include Kan::Abilities

    role :author do |user, post|
      user.id == post.author_id
    end

    register(:read, :edit) { |_, _| true }
    register(:delete) { |_, _| false }
  end

  class AdminAbilities
    include Kan::Abilities

    role :admin do |user, _|
      user.admin?
    end

    register :read, :edit, :delete { |_, _| true }
  end
end

After that we can initialize kan object:

abilities = Kan::Application.new(
  post: [Post::AnonymousAbilities.new, Post::BaseAbilities.new, Post::AuthorAbilities.new, Post::AdminAbilities.new]
  comment: Comments::Abilities.new,
)

And now, we can check can user do something or not:

abilities['post.read'].call(anonymous, post) # => false
abilities['post.read'].call(regular, post)   # => true
abilities['post.read'].call(auther, post)    # => true
abilities['post.read'].call(admin, post)     # => true

abilities['post.edit'].call(anonymous, post) # => false
abilities['post.edit'].call(regular, post)   # => false
abilities['post.edit'].call(auther, post)    # => true
abilities['post.edit'].call(admin, post)     # => true

abilities['post.delete'].call(anonymous, post) # => false
abilities['post.delete'].call(regular, post)   # => false
abilities['post.delete'].call(auther, post)    # => false
abilities['post.delete'].call(admin, post)     # => true

WDYT?

apotonick commented 6 years ago

That works for me! Especially since I see easy ways to compose rules with a DSL on top of this. :kissing_heart:

My next, and still unsolved, thought is: How do we model finer relationships, such as "user is group admin for X and project manager for Y", but I think I can come up with something on top of your kan API and then we can merge.

davydovanton commented 6 years ago

done. You can use roles system from master branch :) https://github.com/davydovanton/kan#roles

apotonick commented 6 years ago

:metal:

Thinking about modeling your abilities in a tree, but I might start that as a kan sub-gem?! BTW, I still have the coolest authorization gem name waiting to become alive, so let me know if you want to change the gem name hahahaha! :joy: :beers: