Simple package for api authorization.
- when you need to restrict access to most endpoints when exposing some to third party developers
- when you don't want to spam your controllers with plugs for every action
- when you must respond according to existing permission system (e.g. scopes in jwt)
- when you need authentication
- when you need authorization for html pages
- when you need advanced permissions management system
def deps do
[{:conductor, "~> 0.4.0"}]
end
Basically, this:
defmodule Controller do
use Conductor # Important! It needs to be before use Phoenix.Controller
use Phoenix.Controller
def index(conn, _params), do: #...
def show(conn, _params), do: #...
@authorize scope: "scope1"
def create(conn, _params), do: #...
@authorize scope: {"scope1", "scope2"}
def update(conn, _params), do: #...
@authorize scope: "scope2"
def delete(conn, _params), do: #...
end
will be compiled to this:
defmodule Controller do
use Conductor
use Phoenix.Controller
plug Conductor.Plugs.Authorize, ["scope1"] when action in [:create]
plug Conductor.Plugs.Authorize, [{"scope1", "scope2"}] when action in [:update]
plug Conductor.Plugs.Authorize, ["scope2"] when action in [:delete]
plug Conductor.Plugs.Authorize, [] when not action in [:create, :update, :delete]
def index(conn, _params), do: #...
def show(conn, _params), do: #...
def create(conn, _params), do: #...
def update(conn, _params), do: #...
def delete(conn, _params), do: #...
end
You can register scope that will have full access everywhere
config :conductor,
root_scopes: ["admin"]
conn |> Plug.Conn.assign(:scopes, ["scope1, scope2"])
defmodule Router do
pipeline :public do
plug Conductor.Plugs.SkipAuthorization
end
scope "/public", MyApp do
pipe_through [:public]
get "/something", SomethingController, :something
end
end
To avoid confusion with random 403
response codes that come from nowhere, Conductor will raise error on authorization failure as default.
This can be changed by following config
config :conductor,
on_auth_failure: :send_resp
#config
config :conductor,
root_scopes: ["root_scope"],
on_auth_failure: :send_resp
#router
pipeline :public do
plug Conductor.Plugs.SkipAuthorization
end
scope "/", Example do
get "/2", Controller, :action2
get "/3", Controller, :action3
get "/4", Controller, :action4
get "/5", Controller, :action5
end
scope "/", Example do
pipe_through [:public]
get "/1", Controller, :action1
end
#conns
conn1 = Phoenix.ConnTest.build_conn()
conn2 = conn1 |> Plug.Conn.assign(:scopes, ["scope1"])
conn3 = conn1 |> Plug.Conn.assign(:scopes, ["scope1", "scope2"])
conn4 = conn1 |> Plug.Conn.assign(:scopes, ["root_scope"])
#endpoints
@authorize scope: "scope1"
def action1(conn, _params), do: conn |> send_resp(200, "")
@authorize scope: "scope2"
def action2(conn, _params), do: conn |> send_resp(200, "")
@authorize scope: {"scope1", "scope2}
def action3(conn, _params), do: conn |> send_resp(200, "")
def action4(conn, _params), do: conn |> send_resp(200, "")
@authorize scopes: ["other", "unused"]
def action5(conn, _params), do: conn |> send_resp(200, "")
| conn1 | conn2 | conn3 | conn4
------- | :---: | :---: | :---: | :---: action1 | 200 | 200 | 200 | 200 action2 | 403 | 200 | 200 | 200 action3 | 403 | 403 | 200 | 200 action4 | 403 | 403 | 403 | 200 action5 | 403 | 403 | 403 | 200
-
Failure response status code
# config/config.exs config :conductor, :failure_status, 418
-
Failure response body
# view defmodule MyApp.Web.ExampleView do use MyApp.Web, :view def render("403.json", _assigns) do %{message: "Forbidden"} end end # config/config.exs config :conductor, :failure_template, {MyApp.Web.ExampleView, "403.json"}
Copyright 2017-2021 Tobiasz Małecki [email protected]
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.