Skip to content

Phoenix, Plug and LiveView integrations for the Permit authorization library.

License

Notifications You must be signed in to change notification settings

curiosum-dev/permit_phoenix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Permit.Phoenix

Phoenix Framework and LiveView integration for Permit authorization library.

Purpose and usage

Permit.Phoenix allows for consistent authorization of actions throughout the entire codebase of a Phoenix application, both in Plug-based controllers and in LiveView.

  • Permit provides the permission definition syntax
  • Permit.Ecto is optional, but - if present - it constructs queries to look up accessible records from a database, based on defined permissions
  • Permit.Phoenix plugs into controllers and live views in order to automatically preload records and check authorization permissions to perform actions.

Installation

The package can be installed by adding permit_phoenix to your list of dependencies in mix.exs:

def deps do
  [
    {:permit_phoenix, "~> 0.1.0"},
    # :permit_ecto can be omitted if Ecto is not used
    {:permit_ecto, "~> 0.1.1"}
  ]
end

Controllers

All options of Permit.Phoenix.Controller can be provided as option keywords with use Permit.Phoenix.Controller or as callback implementations. For example, defining a handle_unauthorized: fn action, conn -> ... end option is equivalent to:

@impl true
def handle_unauthorized(action, conn), do: ...

In practice, it depends on use case:

  • when providing options for different actions, etc., consider using callback implementations
  • if you want to provide values as literals instead of functions, consider using option keywords
  • for global settings throughout controllers using use MyAppWeb, :controller, set globals as keywords, and override in specific controllers using callback implementations.

Whenever resolution_context is referred to, it is typified by Permit.Types.resolution_context.

One-off usage

defmodule MyAppWeb.ArticleController do
  use Permit.Phoenix.Controller,
    # Mandatory options:
    authorization_module: MyApp.Authorization,
    resource_module: MyApp.Article,

    # Additional available options:
    fallback_path: fn action, conn -> ... end,
    handle_unauthorized: fn action, conn -> ... end,
    fetch_subject: fn conn -> ... end,
    preload_actions: [:action1, :action2, ...],
    except: [:action3, :action4, ...],
    id_param_name: fn action, conn -> ... end,
    id_struct_field_name: fn action, conn -> ... end,

    # Non-Ecto only:
    loader: fn resolution_context -> ... end,

    # Ecto only:
    base_query: fn resolution_context -> ... end,
    finalize_query: fn query, resolution_context -> ... end

  def show(conn, params) do
    # If there is a MyApp.Article with ID == params[:id] that
    # matches the current user's permissions, it will be
    # available as the @loaded_resource assign.
    #
    # Otherwise, handle_unauthorized/2 is called, defaulting to
    # redirecting to `/`.
  end

  def index(conn, params) do
    # If the :index action is authorized for the user, the
    # @loaded_resources assign will contain all records accessible
    # by the current user per the app's permissions configuration.
    #
    # Pagination and other concerns can be configured with
    # the base_query/1 callback.
    #
    # Otherwise, handle_unauthorized/2 is called, defaulting to
    # redirecting to `/`.
  end
end

Global usage with settings in specific controllers

defmodule MyAppWeb do
  def controller do
    quote do
      # ...
      use Permit.Phoenix.Controller,
        authorization_module: MyApp.Authorization,
        # global options go here
    end
  end
end

defmodule MyAppWeb.ArticleController do
  use MyAppWeb, :controller

  @impl true
  def resource_module, do: MyAppArticle

  # etc., etc.
end

LiveView

Router configuration

defmodule MyAppWeb.Router do
  # ...

  scope "/", MyAppWeb do
    # ...

    # Configure using an :on_mount hook
    live_session :my_app_session, on_mount: Permit.Phoenix.LiveView.AuthorizeHook do
      # The :live_action names provided here will be
      live "/live/articles", ArticleLive.Index, :index
      live "/live/articles/new", ArticleLive.Index, :new
      live "/live/articles/:id/edit", ArticleLive.Index, :edit

      live "/live/articles/:id", ArticleLive.Show, :show
      live "/live/articles/:id/show/edit", ArticleLive.Show, :edit
    end
  end
end

LiveView configuration

In a similar way to configuring controllers, LiveViews can be configured with option keywords or callback implementations, thus let's omit lengthy examples of both.

Most options are similar to controller options, with socket in place of conn.

Note that it is mandatory to implement the fetch_subject callback, so it is recommended to put it as shared configuration in your web app module.

defmodule PermitTestWeb.ArticleLive.Index do
  use MyAppWeb, :live_view

  use Permit.Phoenix.LiveView,
    authorization_module: MyApp.Authorization,
    resource_module: MyApp.Article

  @impl true
  def mount(_params, _session, socket) do
    # If the :index action is authorized, @loaded_resources assign
    # will contain the list of accessible resources (maybe empty).
    #
    # Pagination, etc. can be configured using base_query/1 callback.
  end

  @impl true
  def handle_params(params, _url, socket) do
    # If assigns[:live_action] has changed, authorization and preloading occurs.
    #
    # If authorized successfully, it is assigned into @loaded_resource or
    # @loaded_resources for singular and plural actions, respectively.
    #
    # If authorization fails, the default implementation of handle_unauthorized/2
    # does:
    #   {:halt, push_redirect(socket, to: "/")}
    # Alternatively you can implement a callback to do something different,
    # for instance you can do {:cont, ...} and assign something to the socket
    # to display a message.
  end

  @impl true
  def fetch_subject(_socket, session) do
    # Retrieve the current user from session
  end
end

About

Phoenix, Plug and LiveView integrations for the Permit authorization library.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages