My permission system requires 3 inputs, how would I design this in elixir?

design
authorization

#1

Ok so in just 1 day I have almost ported my Rails API over to Phoenix, thanks everyone!

So in rails I have a class where I take in a few models as inputs, and based on those models I created my authorization class that I use in my controllers.

class PermissionService
  attr_access :model1, :model2, :model3
  def initialize(model1, model2, model3)
    ...
  end

  def can_do_this?()
    model1.prop1 && model3.prop5
  end

  def can_do_that?()
  end
end

So far in Phoenix I created a custom Plug that I can in my API pipeline, I get the api token from the request and I load etc. using Ecto.

How would I design a module?? to mimick my PermissionService I have in ruby.


#2

You can port that code in a relatively straightforward manner. However, there are probably more idiomatic approaches but it’s hard to suggest them without knowing more concrete details of your use-case. The code below definitely smells more OO than functional.

defmodule MyPermissionService do
  defstruct [:model1, :model2, :model3]

  def new(model1, model2, model3) do
    %__MODULE__{model1: model1, model2: model2, model3: model3}
  end

  def can_do_this?(%__MODULE__{} = service) do
    %__MODULE__{model1: model1, model3: model3} = service
    model1.prop1 && model3.prop5
  end

  ...
end

#3

I would do it with plugs in controller:

def YourController do
  plug :can_do_this when action in [:actions_can_do_this]
  plug :can_do_that when action in [:actions_can_do_that]

  # function plug can_do_this
  defp can_do_this(conn, _) do
  end

  # function plug can_do_that
  defp can_do_that(conn, _) do
  end
end

Of course we can extract those function plugs into its own module.


#4

I would suggest not to carbon copy your rails/ruby code, think for second how can you model this functionally for example I could create a module that implements the functions to check some permission it could be any module instead of taking 1,2,3 models

defmodule PermissionService do
  def can_do_x(list_of_some_model) when is_list(list_of_some_model) do
  end

  def can_do_x(some_model) do 
  end

  def can_do_y(some_model) do
  end
end

not only you can extend this example to accept arbitrary models you can also use it as plugs if you like with minor changes

Note: possible improvements you can create behavior which is implemented by your permission models


#5

Its very fine grained access.

Like say it is forum software:

can access post, can create forum, can reply to post

Update

Thanks for your suggestions, I think I will make it more functional, and also create plugs where it makes sense as sometimes I want the request execution to redirect or halt, and at other times it will be a simple message to the UI or a specific JSON response.