KittyPolicy
Minimalistic authorization library extracted from Product Hunt.
Features:
- small DSL for defining authorization abilities
- not class initializations when performing abilities check
- integrations with GraphQL gem.
Installation
Add this line to your application's Gemfile:
gem 'kitty_policy'
And then execute:
$ bundle
Or install it yourself as:
$ gem install kitty_policy
Usage
Step 1 - Define policy object
module ApplicationPolicy
extend KittyPolicy::DSL
can :moderate do |user|
user.admin?
end
can :start_trial, allow_guest: true do |user, _subscription|
!user || user.trial_used?
end
can :create, :chat_room do |user|
user.admin?
end
can :create, Post do |user|
user.can_post?
end
can :edit, Post do |user, post|
user.admin? || user == post.author
end
can :manage, Account do |user, account|
user.admin? || member?(user, account)
end
private
def member?(user, account)
end
end
can
is just a convince helper to create methods on a module:
ApplicationPolicy.can_moderate?
ApplicationPolicy.can_start_trial?
ApplicationPolicy.can_create_post?
ApplicationPolicy.can_edit_post?
ApplicationPolicy.can_manage_account?
Step 2 - Use policy object
ApplicationPolicy.can?(user, :create, Post)
ApplicationPolicy.can?(user, :create, Post.new)
ApplicationPolicy.can?(user, :create, post)
ApplicationPolicy.can?(user, :start_trial)
ApplicationPolicy.authorize!(user, :create, Post)
ApplicationPolicy.authorize!(user, :create, Post.new)
ApplicationPolicy.authorize!(user, :create, post)
ApplicationPolicy.authorize!(user, :start_trial)
(Optional Step) - Group policies into separate files
You can split your logic into multiple policy files:
module Posts::Policy
extend KittyPolicy::DSL
end
Then you can group them together.
module ApplicationPolicy
extend Posts::Policy
extend Ship::Policy
end
Testing with RSpec
require 'spec_helper'
require 'kitty_policy/rspec'
describe ApplicationPolicy do
include KittyPolicy::RSpec
describe 'can_moderate?' do
it 'returns true for admin' do
expect(User.new(admin: true)).to be_able_to :moderate
end
it 'returns false for everyone else' do
expect(User.new(admin: false)).not_to be_able_to :moderate
end
end
end
Delegating abilities
module ApplicationPolicy
extend KittyPolicy::DSL
can :edit, Post do |user, post|
user.id == post.user_id
end
can :edit, PostMedia do |user, media|
can? user, :edit, media.post
end
can :destroy, PostMedia do |user, media|
can? user, :edit, media.post
end
delegate_ability :edit, PostMedia, to: :post
delegate_ability :destroy, PostMedia, to: :post, to_ability: :edit
Integration with GraphQL
Field level authorization
require 'kitty_policy/graphql/field_authorization'
class ProductHuntSchema < GraphQL::Schema
instrument :field, KittyPolicy::GraphQL::FieldAuthorization.new(
policy: ApplicationPolicy,
current_user_key: :current_user,
)
end
module Types
class PostType < BaseObject
field :metrics, [MetricType], null: false, authorize: :edit, fallback: []
field :moderation_changes_count, Integer, null: false, authorize: :moderate, fallback: 0
end
end
module Types
class QueryType < BaseObject
field :post, PostType, null: false, authorize_object: :view, fallback: nil do
argument :id, ID, required: true
end
field :post, PostType, null: false, authorize_object: :view do
argument :id, ID, required: true
end
end
end
Can resolver
Exposes if current user can perform certain action.
require 'kitty_policy/graphql/can_resolver'
module Resolvers
Can = KittyPolicy::GraphQL::CanResolver.new(
policy: ApplicationPolicy,
current_user_key: :current_user,
base_resolver: BaseResolver,
)
end
module Types
class PostType < BaseObject
field :can_edit, resolver: Resolvers::Can.perform(:edit)
field :can_moderate, resolver: Resolvers::Can.perform(:moderate) { :site }
end
end
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Run the tests (
rake
) - Create new Pull Request
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the KittyPolicy project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.