pow-auth / pow

Robust, modular, and extendable user authentication system
https://powauth.com
MIT License
1.59k stars 153 forks source link

Multitenancy without multiple schemas #577

Open choallin opened 3 years ago

choallin commented 3 years ago

I have an app where I need multitenancy without schemas.
I have a column in the users table which I use for that. How can I achieve this with pow? Is there a repository function that I can implement to use for a user lookup?

danschultzer commented 3 years ago

This is pretty application specific, but you would likely need something similar to the multitenancy guide: https://hexdocs.pm/pow/1.0.21/multitenancy.html#content

As you fetch the tenant in the conn, you would then pass that value on to the repo to use for any calls thereafter. I would use the :repo_opts for that, and implement a custom MyApp.MultitenancyRepo module. That repo module needs to implement get_by/3, delete/2, insert/2 and update/2 where you handle the table-based multitenancy by pulling the tenant from the :repo_opts, modify the query in get_by/2 or the changeset in the other functions, and then call MyApp.Repo.

choallin commented 3 years ago

Sorry to come back to this again. :-/ I have a created this repo as you mentioned, also I am trying to fetch the data from the conn which is working for me.
But I don't know how to configure this custom "repo" to have access to this tenant_id field.
Here is what I have done so far:

Fetching the subdomain to access the tenant name:

defmodule AppointmentManagerWeb.Pow.TenantPlug do
  def init(config), do: config

  def call(conn, config) do
    subdomain = conn.host |> String.split(".") |> List.first
    config = Keyword.put(config, :repo_opts, [prefix: subdomain])

    Pow.Plug.Session.call(conn, config)
  end
end

endpoint.ex

plug Plug.Session,
    store: :cookie,
    key: "_my_app_key",
    signing_salt: "stuff"

  plug MyApp.Pow.TenantPlug
  plug Pow.Plug.Session,
    otp_app: :my_app,
    credentials_cache_store: {Pow.Store.CredentialsCache,
                              ttl: :timer.minutes(60*12),
                              namespace: "credentials"}

pow config:

config :my_app, :pow,
  user: MyApp.Users.User,
  repo: MyApp.MultitenancyRepo,
  extensions: [PowResetPassword],
  controller_callbacks: Pow.Extension.Phoenix.ControllerCallbacks,
  mailer_backend: MyApp.Mailer,
  web_module: MyAppWeb,
  users_context: MyApp.Users

What do I have to do, to get access to the configuration in my "Repo"?