Canary.Plugs (canary v1.2.0)
Plug functions for loading and authorizing resources for the current request.
The plugs all store data in conn.assigns (in Phoenix applications, keys in conn.assigns can be accessed with @key_name in templates)
In order to use the plug functions, you must use Canary.
You must also specify the Ecto repo to use in your configuration:
config :canary, repo: Project.RepoIf you wish, you may also specify the key where Canary will look for the current user record to authorize against:
config :canary, current_user: :some_current_userYou can specify a handler function (in this case, Helpers.handle_unauthorized) to be called when an action is unauthorized like so:
config :canary, unauthorized_handler: {Helpers, :handle_unauthorized}or to handle when a resource is not found:
config :canary, not_found_handler: {Helpers, :handle_not_found}Canary will pass the conn to the handler function.
Summary
Functions
Authorize the current user against the calling controller.
Authorize the current user for the given resource.
Authorize the given resource and then load it if authorization succeeds.
Load the given resource.
Functions
Authorize the current user against the calling controller.
In order to use this function,
conn.assigns[Application.get_env(:canary, :current_user, :current_user)]must be an ecto struct representing the current userconn.privatemust be a map (this should not be a problem unless you explicitly modified it)
authorize_controller checks for the name of the current controller in one of the following places
- :phoenix_controller in conn.private
- :canary_controller in conn.assigns
In case you are not using phoenix, make sure you set the controller name in the conn.assigns
Note that in case neither of :phoenix_controller or :canary_controller are found the requested
authorization won't necessarily fail, rather it will trigger a .can? function with a nil controller
If authorization succeeds, sets conn.assigns.authorized to true.
If authorization fails, sets conn.assigns.authorized to false.
Optional opts:
:only- Specifies which actions to authorize:except- Specifies which actions for which to skip authorization:unauthorized_handler- Specify a handler function to be called if the action is unauthorized
Examples:
plug :authorize_controller
plug :authorize_controller, only: [:index, :show]
plug :authorize_controller, except: [:destroy]
Authorize the current user for the given resource.
In order to use this function,
conn.assigns[Application.get_env(:canary, :current_user, :current_user)]must be an ecto struct representing the current userconn.privatemust be a map (this should not be a problem unless you explicitly modified it)
If authorization succeeds, sets conn.assigns.authorized to true.
If authorization fails, sets conn.assigns.authorized to false.
For the :index, :new, and :create actions, the resource in the Canada.Can implementation
should be the module name of the model rather than a struct. A struct should be used instead of
the module name only if the :persisted key is used and you want to override the default
authorization behavior. This can be useful when dealing with nested resources.
For example:
use
def can?(%User{}, :index, Post), do: trueinstead of
def can?(%User{}, :index, %Post{}), do: trueor
use
def can?(%User{id: user_id}, :index, %Post{user_id: user_id}), do: trueif you are dealing with a nested resource, such as, "/post/post_id/comments"
You can specify additional actions for which Canary will authorize based on the model name, by passing the non_id_actions opt to the plug.
For example,
plug :authorize_resource, model: Post, non_id_actions: [:find_by_name]Required opts:
:model- Specifies the module name of the model to authorize access to
Optional opts:
:only- Specifies which actions to authorize:except- Specifies which actions for which to skip authorization:preload- Specifies association(s) to preload:id_name- Specifies the name of the id inconn.params, defaults to "id":id_field- Specifies the name of the ID field in the database for searching :id_name value, defaults to "id".:persisted- Specifies the resource should always be loaded from the database, defaults to false:unauthorized_handler- Specify a handler function to be called if the action is unauthorized
Examples:
plug :authorize_resource, model: Post
plug :authorize_resource, model: User, preload: :posts
plug :authorize_resource, model: User, only: [:index, :show], preload: :posts
plug :load_resource, model: Post, id_name: "post_id", only: [:index], persisted: true, preload: :comments
plug :load_resource, model: Post, id_name: "slug", id_field: "slug", only: [:show], persisted: true
Authorize the given resource and then load it if authorization succeeds.
If the resource cannot be loaded or authorization fails, conn.assigns.resource_name is set to nil.
The result of the authorization (true/false) is assigned to conn.assigns.authorized.
Also, see the documentation for load_resource/2 and authorize_resource/2.
Required opts:
:model- Specifies the module name of the model to load resources from
Optional opts:
:as- Specifies theresource_nameto use:only- Specifies which actions to authorize:except- Specifies which actions for which to skip authorization:preload- Specifies association(s) to preload:id_name- Specifies the name of the id inconn.params, defaults to "id":id_field- Specifies the name of the ID field in the database for searching :id_name value, defaults to "id".:unauthorized_handler- Specify a handler function to be called if the action is unauthorized:not_found_handler- Specify a handler function to be called if the resource is not found
Note: If both an :unauthorized_handler and a :not_found_handler are specified for load_and_authorize_resource,
and the request meets the criteria for both, the :unauthorized_handler will be called first.
Examples:
plug :load_and_authorize_resource, model: Post
plug :load_and_authorize_resource, model: User, preload: :posts, as: :the_user
plug :load_and_authorize_resource, model: User, only: [:index, :show], preload: :posts, as: :person
plug :load_and_authorize_resource, model: User, except: [:destroy]
plug :load_and_authorize_resource, model: Post, id_name: "slug", id_field: "slug", only: [:show], persisted: true
Load the given resource.
Load the resource with id given by conn.params["id"] (or conn.params[opts[:id_name]] if opts[:id_name] is specified)
and ecto model given by opts[:model] into conn.assigns.resource_name.
resource_name is either inferred from the model name or specified in the plug declaration with the :as key.
To infer the resource_name, the most specific(right most) name in the model's
module name will be used, converted to underscore case.
For example, load_resource model: Some.Project.BlogPost will load the resource into
conn.assigns.blog_post
If the resource cannot be fetched, conn.assigns.resource_name is set
to nil.
By default, when the action is :index, all records from the specified model will be loaded. This can
be overridden to fetch a single record from the database by using the :persisted key.
Currently, :new and :create actions are ignored, and conn.assigns.resource_name
will be set to nil for these actions. This can be overridden to fetch a single record from the database
by using the :persisted key.
The :persisted key can override how a resource is loaded and can be useful when dealing
with nested resources.
Required opts:
:model- Specifies the module name of the model to load resources from
Optional opts:
:as- Specifies theresource_nameto use:only- Specifies which actions to authorize:except- Specifies which actions for which to skip authorization:preload- Specifies association(s) to preload:id_name- Specifies the name of the id inconn.params, defaults to "id":id_field- Specifies the name of the ID field in the database for searching :id_name value, defaults to "id".:persisted- Specifies the resource should always be loaded from the database, defaults to false:not_found_handler- Specify a handler function to be called if the resource is not found:required- Same as:persistedbut with not found handler - even for :index, :new or :create action
Examples:
plug :load_resource, model: Post
plug :load_resource, model: User, preload: :posts, as: :the_user
plug :load_resource, model: User, only: [:index, :show], preload: :posts, as: :person
plug :load_resource, model: User, except: [:destroy]
plug :load_resource, model: Post, id_name: "post_id", only: [:new, :create], persisted: true
plug :load_resource, model: Post, id_name: "slug", id_field: "slug", only: [:show], persisted: true