Simple policy checks based with relationships
Hello, friends!
So on the website documentation, we have an example of a simple policy check:
All well and good, but in a more real world example we'd probably have:
- Roles for Users
- Many permissions for those roles
- Potentially many permissions for users
So let's say we have something like the following:
A
And you want to check both the role, the permissions a role has and user permissions.
My question would be how do we go about doing the simple policy checks when we have a role-permission setup like this? Because the check itself isn't complex, it's more of a "how do we get there" question.
# we're inside of a module here
def match?(%MyApp.User{age: age} = _actor, %{resource: MyApp.Beer} = _context, _opts) do
age >= 21
end
# we're inside of a module here
def match?(%MyApp.User{age: age} = _actor, %{resource: MyApp.Beer} = _context, _opts) do
age >= 21
end
User
resource:
defmodule MyApp.Accounts.User do
@moduledoc """
Close to a real world example of a basic users, but
obviously there's a lot more stuff here.
Shortened for the sake of brevity.
"""
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication]
postgres do
table "app_users"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :first_name, :ci_string, allow_nil?: false
attribute :last_name, :ci_string, allow_nil?: false
attribute :email, :ci_string, allow_nil?: false, sensitive?: true
attribute :hashed_password, :string, allow_nil?: false, sensitive?: true
create_timestamp(:created_at)
update_timestamp(:updated_at)
end
relationships do
has_one :role, MyApp.Accounts.Role
many_to_many :permissions, MyApp.Accounts.User do
through MyApp.Accounts.UserPermission
source_attribute_on_join_resource :user_id
destination_attribute_on_join_resource :permission_id
end
end
defmodule MyApp.Accounts.User do
@moduledoc """
Close to a real world example of a basic users, but
obviously there's a lot more stuff here.
Shortened for the sake of brevity.
"""
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication]
postgres do
table "app_users"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :first_name, :ci_string, allow_nil?: false
attribute :last_name, :ci_string, allow_nil?: false
attribute :email, :ci_string, allow_nil?: false, sensitive?: true
attribute :hashed_password, :string, allow_nil?: false, sensitive?: true
create_timestamp(:created_at)
update_timestamp(:updated_at)
end
relationships do
has_one :role, MyApp.Accounts.Role
many_to_many :permissions, MyApp.Accounts.User do
through MyApp.Accounts.UserPermission
source_attribute_on_join_resource :user_id
destination_attribute_on_join_resource :permission_id
end
end
3 Replies
To give some more clarity, here's some other resources:
A
A
And of course...
A
A
RolePermission
resource:
defmodule MyApp.Accounts.RolePermission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "role_permissions"
repo MyApp.Repo
end
relationships do
belongs_to :role, MyApp.Accounts.Role do
primary_key? true
allow_nil? false
end
belongs_to :permission, MyApp.Accounts.Permission do
primary_key? true
allow_nil? false
end
end
end
defmodule MyApp.Accounts.RolePermission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "role_permissions"
repo MyApp.Repo
end
relationships do
belongs_to :role, MyApp.Accounts.Role do
primary_key? true
allow_nil? false
end
belongs_to :permission, MyApp.Accounts.Permission do
primary_key? true
allow_nil? false
end
end
end
UserPermission
resource:
defmodule MyApp.Accounts.UserPermission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "user_permissions"
repo MyApp.Repo
end
relationships do
belongs_to :user, MyApp.Accounts.User do
primary_key? true
allow_nil? false
end
belongs_to :permission, MyApp.Accounts.Permission do
primary_key? true
allow_nil? false
end
end
end
defmodule MyApp.Accounts.UserPermission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "user_permissions"
repo MyApp.Repo
end
relationships do
belongs_to :user, MyApp.Accounts.User do
primary_key? true
allow_nil? false
end
belongs_to :permission, MyApp.Accounts.Permission do
primary_key? true
allow_nil? false
end
end
end
Role
resource:
defmodule MyApp.Accounts.Role do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "roles"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :name, :string do
allow_nil? false
end
attribute :description, :string do
allow_nil? false
end
end
relationships do
has_many :users, MyApp.Accounts.User
many_to_many :permissions, MyApp.Accounts.Role do
through MyApp.Accounts.RolePermission
source_attribute_on_join_resource :role_id
destination_attribute_on_join_resource :permission_id
end
end
end
defmodule MyApp.Accounts.Role do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "roles"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :name, :string do
allow_nil? false
end
attribute :description, :string do
allow_nil? false
end
end
relationships do
has_many :users, MyApp.Accounts.User
many_to_many :permissions, MyApp.Accounts.Role do
through MyApp.Accounts.RolePermission
source_attribute_on_join_resource :role_id
destination_attribute_on_join_resource :permission_id
end
end
end
Permission
resource:
defmodule MyApp.Accounts.Permission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "permissiones"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :name, :string do
allow_nil? false
end
attribute :description, :string do
allow_nil? false
end
end
relationships do
many_to_many :roles, MyApp.Accounts.Permission do
through MyApp.Accounts.RolePermission
source_attribute_on_join_resource :permission_id
destination_attribute_on_join_resource :role_id
end
many_to_many :users, MyApp.Accounts.Permission do
through MyApp.Accounts.UserPermission
source_attribute_on_join_resource :permission_id
destination_attribute_on_join_resource :user_id
end
end
end
defmodule MyApp.Accounts.Permission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "permissiones"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :name, :string do
allow_nil? false
end
attribute :description, :string do
allow_nil? false
end
end
relationships do
many_to_many :roles, MyApp.Accounts.Permission do
through MyApp.Accounts.RolePermission
source_attribute_on_join_resource :permission_id
destination_attribute_on_join_resource :role_id
end
many_to_many :users, MyApp.Accounts.Permission do
through MyApp.Accounts.UserPermission
source_attribute_on_join_resource :permission_id
destination_attribute_on_join_resource :user_id
end
end
end
👋 this support channel is archived, would you mind posting on the Elixir Forum instead please?
Oh whoops! Of course!