Prawo do wejścia na dokument

Prawo do wejścia na dokument
  • Rejestracja: dni
  • Ostatnio: dni
0

Załózmy, że mam taką metodę w kontrolerze

Kopiuj
    // GET Mapping
    public function edit($documentId)
    {
        $document = $this->documentRepository->getOrFail($documentId);
        $details = $document->details;

        $locations = $this->locationRepository
                            ->getBy('customer_id', $document->customer_id)
                            ->pluck('location_name', 'id');

        $customers = $this->customerRepository
                            ->getBy('id', Auth::user()->customer_id)
                            ->pluck('name', 'id');

        $animals = $this->animalRepository->getAll()->pluck('name', 'id');

        $races = collect();

        return view('document.document', compact('document', 'locations', 'customers', 'animals', 'races', 'details'));
    }

i teraz mam dwa pytania:

  1. Ważniejsze :) jak ograniczyć wejście do tej metody w taki sposób aby Admin mógł zawsze to zrobić a user mógł wejśc tylko do dokumentu należącego do jego firmy ( model Document ma pole customer_id, z kolei User ma customer_id )
    Laravelowo CHYBA trzeba by użyć Policy ale nie rozumiem jak tego użyć. Czy ktoś z Was mógłby zarzucić kawałkiem kodu.
    Aha moja struktura wygląda tak. User, Roles, User_Roles. Nie mam żadnych permissions i na razie tak ma zostać.

  2. Mniej ważne - czy mogłbym tą metodę jakoś ładniej zapisać? Uzyć serwisu, który by mi zwrócił $locations, $customers, $animals, $races? Czy zostawić tak jak jest? Całe "bebechy wpakować w serwis....

Patryk27
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 13042
0

Laravelowo CHYBA trzeba by użyć Policy

Tak, powinieneś napisać politykę (policy) i połączyć ją z routingiem.
W dokumentacji Laravela jest o tym cała sekcja - rzuciłeś tam okiem? (a jeśli tak - czego konkretniej nie rozumiesz?)

czy mogłbym tą metodę jakoś ładniej zapisać?

  1. $details = $document->details; - niepotrzebnie to wydzielasz do zmiennej, w widoku możesz przecież się odwoływać do $document->details.

  2. $locations = $this->locationRepository ... - IMHO powinieneś mieć związek $document->customerLocations, chociaż nie jest to jasne.

  3. $customers = $this->customerRepository ... - czy to nie jest równoważne z $customer = Auth::user()->customer? Jeśli nie, taki właśnie związek z modelu User powinieneś utworzyć.

Reszta wygląda ok, chociaż personalnie nie jestem fanem compact - kiedyś przypadkowo zrefaktoryzujesz nazwę zmiennej i nawet nie zauważysz, że widok przestał Ci działać.

  • Rejestracja: dni
  • Ostatnio: dni
0

Patryk utworyrzyłem testowo taką klasę

Kopiuj
class DocumentPolicy
{
    use HandlesAuthorization;


    public function __construct()
    {
        //
    }

    public function showDocument(User $user, Document $document)
    {
        if($user->customer->id === $document->customer_id)
        {
            return true;
        }
        elseif ($user->hasAnyRole([User::ROLE_ADMINISTRATOR, User::ROLE_SALESMANAGER])) {
            return true;
        }

        return false;
    }
}

w AppServiceProvider dodałem

Kopiuj
    protected $policies = [
        Document::class => DocumentPolicy::class,
    ];

nie wiem czy działa bo nie do końca teraz wiem jak tego użyć? to raz, a dwa nie rozumiem koneksji nazw tych polityk z metodami w kontrolerach....

Patryk27
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 13042
0

nie rozumiem koneksji nazw tych polityk z metodami w kontrolerach....

Nie istnieje żadne połączenie wprost polityka <-> dokument - dopiero Ty je ustalasz.

Możesz wymagać, aby np. akcja edytuj użytkownika wymagała polityk czy zalogowany użytkownik może edytować innych? oraz czy zalogowany użytkownik może edytować tego konkretnego użytkownika?.

Mają taki zestaw jak wyżej (tzn. kod, który już masz), możesz do tego podejść na wiele spososów:
https://laravel.com/docs/5.5/authorization#authorizing-actions-using-policies

  • Rejestracja: dni
  • Ostatnio: dni
0

tam miałem błąd w polityce

Kopiuj
    public function showDocument(User $user, Document $document)
    {
        if($user->customer_id === $document->customer_id)  // miałem $user->customer->id fuj
        {
            return true;
        }
        elseif ($user->hasAnyRole([User::ROLE_ADMINISTRATOR, User::ROLE_SALESMANAGER])) {
            return true;
        }

        return false;
    }

i zobacz

próba nr 1:
w metodzie edit

Kopiuj
$this->authorize('showDocument', Document::class);

dodaję zawsze brzydki komunikat "This action is unauthorized."

próba nr 2:

Kopiuj
Route::get('/document/{id}', 'Document\DocumentController@edit')->name('documentedit')->middleware('can:showDocument, document');

dodaję zawsze brzydki komunikat "This action is unauthorized."

Patryk27
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 13042
0

Spróbuj wrzucić na pałę return true; do metody polityki i sprawdź ponownie.

Jeśli nadal będzie to samo, to:

  1. Być może nie rejestrujesz poprawnie polityki (masz wywołanie $this->registerPolicies(); w providerze?).

  2. Być może masz gdzieś literówkę (w Laraverze nie ma błędu w stylu Polityka [foo] dla modelu [bar] nie istnieje., tylko od razu oberwiesz błąd unauthorized).

  • Rejestracja: dni
  • Ostatnio: dni
0

pomyliłem i dałem w AppServiceProvider zamiast w AuthServiceProvider, poprawione - nadal to samo, gdy w metodzie polityki dałem tylko return true; - to samo.
A powiedz, bo tego nie rozumiem....
Metoda polityki - showDocument
i teraz mogę albo w kontrolerze w mojej metodzie edit zapodać tak

Kopiuj
$this->authorize('edit', Document::class);  // czy powinno być authorize('metodaPolityki' ....

to samo w web.php

Kopiuj
->middleware('can:edit,App\Models\Document');  // czy can:metodaPolityki
Patryk27
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 13042
0

$this->authorize('metodaPolityki', $model), tak samo w middleware'ach.

Przy czym w middleware'ach powinieneś mieć can:metodaPolityki,nazwaParametru (tak jak tutaj: https://laravel.com/docs/5.5/authorization#via-middleware).

Jeśli mimo return true; otrzymujesz błąd, to albo źle rejestrujesz politykę (wrzuć jakieś die('cośtam'); na początek pliku, aby zobaczyć czy w ogóle wczytuje), albo robisz gdzieś po drodze literówkę.

  • Rejestracja: dni
  • Ostatnio: dni
0

rejestracja jest ok. Dałem wczesniej die() w polityce i usunąłem parametry tej metody i wszedłem tam.
gdy wywołuję w kontrolerze

Kopiuj
$this->authorize('showDocument', Document::class);

dostaję
Type error: Argument 2 passed to App\Policies\DocumentPolicy::showDocument() must be an instance of App\Models\Document, none given, called in /var/www/html/iferma/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 466

p.s. Jak robisz bb code na czerwono ?

Patryk27
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 13042
0

Twoja metoda w polityce oczekuje konkretnego dokumentu, zatem powinieneś zrobić $this->authorize('showDocument', $document);.

Jak robisz bb code na czerwono ?

Zawsze możesz zacytować posta i przekonać się ;-)
Backtickami.

  • Rejestracja: dni
  • Ostatnio: dni
0

kiedy mam

Kopiuj
    public function showDocument()
    {
        die('here');        
        return true;
    }

i w kontrolerze

Kopiuj
$this->authorize('showDocument', Document::class);

dostaję na ekranie "here"

kiedy mam tak

Kopiuj
    public function showDocument(User $user, Document $document)
    {
       die('here');
        return true;
    }

i wywołam tak

Kopiuj
$this->authorize('showDocument', Document::class);

dostaje
Type error: Argument 2 passed to App\Policies\DocumentPolicy::showDocument() must be an instance of App\Models\Document, none given, called in /var/www/html/iferma/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 466

kiedy wywołam tak

Kopiuj
$this->authorize('showDocument', [User::class, Document::class]);

dostaje This action is unauthorized.

jadę na obiad :)

Patryk27
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 13042
0

Musisz przekazać konkretny obiekt.

Z tym wyjątkiem, że User jest przekazywane domyślnie.

  • Rejestracja: dni
  • Ostatnio: dni
0

tak jest OK

Kopiuj
    public function showDocument(User $user, Document $document)
    {
        if($user->customer_id === $document->customer_id)
        {
            return true;
        }
        elseif ($user->hasAnyRole([User::ROLE_ADMINISTRATOR, User::ROLE_SALESMANAGER])) {
            return true;
        }

        return false;
    }

i kontroler

Kopiuj
   public function edit($documentId)
    {
        $document = $this->documentRepository->getOrFail($documentId);

        // check if user can see the document
        $this->authorize('showDocument', $document);

        //........
    }

dziękuje @Patryk27

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.