Prawo do wejścia na dokument

0

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

    // 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....

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ć.

0

Patryk utworyrzyłem testowo taką klasę

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

    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....

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

0

tam miałem błąd w polityce

    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

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

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

próba nr 2:

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

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

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).

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

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

to samo w web.php

->middleware('can:edit,App\Models\Document');  // czy can:metodaPolityki
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ę.

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

$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 ?

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.

0

kiedy mam

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

i w kontrolerze

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

dostaję na ekranie "here"

kiedy mam tak

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

i wywołam tak

$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

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

dostaje This action is unauthorized.

jadę na obiad :)

0

Musisz przekazać konkretny obiekt.

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

0

tak jest OK

    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

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

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

        //........
    }

dziękuje @Patryk27

1 użytkowników online, w tym zalogowanych: 0, gości: 1