Utilizzo la gemma Pundit (con Devise e Rolify) per limitare l'accesso alle informazioni in base ai ruoli utente registrati.Implementazione di ambiti in Pundit
In questo momento sono definiti tre ruoli per il modello Utente: Amministratore, Amministratore cliente e Amministratore cliente.
Un utente appartiene a un cliente. Il cliente ha molti utenti.
Ho implementato correttamente un criterio Pundit quando indicizza il modello Cliente. Amministratori e amministratori clienti possono vedere tutti i clienti. L'amministratore del cliente può vedere solo il proprio record PROPRIO.
Il problema si trova quando si tenta di limitare il metodo show del controller del cliente. Amministratori e amministratori clienti possono vedere tutti i clienti. Tuttavia, l'amministratore del cliente dovrebbe essere in grado di vedere solo il proprio record. Ma così com'è l'amministratore del cliente può inserire qualsiasi id nell'URL e vedere qualsiasi record del cliente.
Sono confuso sullo scoping. Sono a conoscenza del fatto che i metodi della politica (cioè l'indice e lo spettacolo?) Limitano l'OMS in grado di eseguire queste azioni e che i metodi di Scoping limitano QUALI RECORD possono essere ottenuti. Ho difficoltà a comporre l'ambito corretto per lo scenario sopra.
Ecco il controller clienti:
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
after_action :verify_authorized
# GET /customers
# GET /customers.json
def index
@customers = policy_scope(Customer)
authorize Customer
end
# GET /customers/1
# GET /customers/1.json
def show
authorize @customer
end
# GET /customers/new
def new
@customer = Customer.new
authorize @customer
end
# GET /customers/1/edit
def edit
authorize @customer
end
# POST /customers
# POST /customers.json
def create
@customer = Customer.new(customer_params)
authorize @customer
respond_to do |format|
if @customer.save
format.html { redirect_to @customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: @customer }
else
format.html { render :new }
format.json { render json: @customer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /customers/1
# PATCH/PUT /customers/1.json
def update
authorize @customer
respond_to do |format|
if @customer.update(customer_params)
format.html { redirect_to @customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: @customer }
else
format.html { render :edit }
format.json { render json: @customer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /customers/1
# DELETE /customers/1.json
def destroy
authorize @customer
@customer.destroy
respond_to do |format|
format.html { redirect_to customers_url, notice: 'Customer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
@customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:name, :parent_customer_id, :customer_type, :active, :currency)
end
end
E qui è la politica del cliente:
class CustomerPolicy < ApplicationPolicy
def index?
# Admins, ClientAdmins, and CustomerAdmins can index customers (see Scope class for filters)
@user.has_role? :admin or @user.has_role? :client_admin or @user.has_role? :customer_admin
end
def show?
# Admins, ClientAdmins, and CustomerAdmins can see any customer details
@user.has_role? :admin or @user.has_role? :client_admin or @user.has_role? :customer_admin
end
def update?
# Only Admins and ClientAdmins can update customer details
@user.has_role? :admin or @user.has_role? :client_admin
end
def destroy?
@user.has_role? :admin or @user.has_role? :client_admin
end
class Scope < Struct.new(:user, :scope)
def resolve
if (user.has_role? :admin or user.has_role? :client_admin)
# Admins and ClientAdmins can see all Customers
scope.where(:parent_id => nil)
elsif user.has_role? :customer_admin
# Customer Admins can only see their own Customer
scope.where(:id => user.customer) # THIS DOES NOT APPEAR TO GET INVOKED BY THE SHOW METHOD OF THE CONTROLLER
end
end
def show?
# NOT SURE WHAT TO PUT IN HERE
end
end
end
Successo !! Grazie all'avvio da me fornito dalla railscard, il trucco era modificare lo spettacolo? metodo nel file politica di cliente come il seguente:
def show?
# Admins, ClientAdmins, and CustomerAdmins can see any customer details
# Students cannot see customer details
return true if user.has_role?(:admin) || user.has_role?(:client_admin)
return true if user.customer_id == @record.id && user.has_role?(:customer_admin)
false
end
Nota che ho dovuto utilizzare la variabile di istanza @record, come è quello che utilizza la classe politica di applicazione di fare riferimento al record di essere passato dal metodo di autorizzare.
Grazie !!
Grazie in anticipo per l'aiuto. Capisco cosa stai dicendo - lo scope dovrebbe essere usato quando mi aspetto di restituire una collezione. Ma non sono sicuro di dove mettere questo metodo che hai descritto. Sarebbe nella politica del cliente? Scusate. Questo mi sta facendo sentire completamente stupido. –
Per essere chiari: ho provato a inserire il metodo nel file dei criteri cliente e non vedo alcuna differenza di comportamento. Immagino di non essere sicuro di cosa scatenerebbe quel metodo. –
OTTENUTO! Sei il mio eroe grazie mille. Inserirò il codice revisionato nella domanda, ma questa era quasi la risposta giusta. –