Skip to content

lenra-io/bouncer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Contributors Forks Stargazers Issues MIT License


Bouncer

Bouncer is a simple library that allow to create your permission policy using a simple behavior. It was built with Phoenix framework in mind but can be adapted to many more situations.
Built With Elixir

Report Bug · Request Feature

Installation

The package is curently not available in hexpm but we are planning to add it in a near future.

In the meantime you can add it to your project dependancies using git.

def deps do
  [
    {:bouncer, git: "https://github.com/lenra-io/bouncer.git", tag: "vx.y.z"}
  ]
end

(back to top)

Usage

Bouncer is designed around the Bouncer.Policy behavior. You just have to create a MyApp.Policy module and implement the authorize/3 function. The following example are used with Phoenix controllers.

# First we define the Policy using the behavior for a specific Controller
defmodule MyApp.MyController.Policy do
  @behaviour Bouncer.Policy

  @impl true
  # The authorize/3 function take:  
  # - the atom representing the current user action
  # - the user struct/map or anything that represent a resource/user/account
  # - Any metadata useful to check permissions

  # If the user is an admin, he can do everything
  def authorize(_, %User{role: :admin}, _), do: true
  # any one can acces the index page
  def authorize(:index, _, _), do: true
  # Only verified user can create the resource
  def authorize(:create, %User{role: :verified_user}, _), do: true
  # Only the owner of the resource can update or delete the resource.
  # We use pattern matching on id to ensure that the id is the same.
  # If the id of the user and the user owner is different, it will not match.
  # We also use guard to group the rule of :create and :delete
  def authorize(action, %User{id: id}, %Resource{owner: User{id: id}}) when action in [:create, :delete], do: true
  # Good practice, deny everything else baseline.
  def authorize(_, _, _), do: false
end

Now that the policy is defined, you just have to use Bouncer.allow/4 or Bouncer.allow?/4 to check if the given resource can do the given action with a given metadata.

defmodule MyApp do
  # The allow/3 function is designed to be used inside the `with` flow control.
  # the allow?/3 function can be use in Enum.filter, if...
  def index do
    with {:ok, user} <- fetch_my_user(),
          :ok <- Bouncer.allow(MyApp.Policy, :index, user, nil) do
      do_my_stuff()
    end
  end
end

Since this can add a lot of repetitive code such as fetching user, specify the module and the action, you can also create some macro to help you shorten the Bouncer.allow call.

In this example, we will create a macro that will automatically extract the user from the conn and pass the Policy module and the controller action. This will transform the allow/4 function into a allow/2 function that take the conn and the metadata.

defmodule MyApp.Policy do

  defmacro __using__(opts \\ []) do
    policy_module = Keyword.get(opts, :module)

    quote do
      @spec allow(any(), any()) :: :ok | {:error, atom()}
      def allow(conn, params \\ nil) do
        Bouncer.allow(
          unquote(policy_module),
          Plug.action_name(conn),
          get_user(conn),
          params
        )
      end
    end
  end
end

Then, use it on the Phoenix controller like so

defmodule MyApp.MyController do
  use MyApp, :controller

  use MyApp.Policy,
    module: MyApp.MyController.Policy

  def index(conn, %{id: resource_id}) do
    with {:ok, resource} <- fetchResource(resource_id)
        :ok <- allow(conn, resource) do
      doStuff()
    end
  end


end

(back to top)

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please open an issue with the tag "enhancement". Don't forget to give the project a star if you liked it! Thanks again!

(back to top)

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Contact

Lenra - @lenra_dev - contact@lenra.io

Project Link: https://github.com/lenra-io/bouncer

(back to top)

About

A simple elixir library to handle permissions

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Languages