Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Como fazer com que o usuário só tenha acesso ao que é dele?

Estou criando uma TodoList para praticar o que aprendi no curso. Tenho uma tabela todo_lists que contém uma chave estrangeira que referencia a um usuário. Já criei o CRUD completo de todo_lists e já rodei o php artisan make:auth para fazer o scaffold de autenticação. Eu gostaria de saber como que eu faço para que o usuário logado só tenha acesso ao que está referenciado com seu id(show, index, edit, update, delete). Atualmente na página index de todo_lists eu até consigo mostrar só as listas do usuário logado com o seguinte código:

 public function index()
    {
        $user = User::find(Auth::user()->id);
        $todo_lists = $user->todo_lists;
        return view('todo_list.index')->with('todo_lists', $todo_lists);
    }

O problema é que eu consigo acessar uma URL com uma todo_list criada por outro usuário, comportamento esse que eu não quero. Por exemplo:

http://localhost:8000/todo_list/3/edit http://localhost:8000/todo_list/3 http://localhost:8000/todo_list/3 - com destroy ...

Digamos que essa todo_list de id 3 foi criada por outro usuário então eu o comportamento que espero é uma página 404 ou então de permissão negada.Como é que eu faço isso?

3 respostas

Sugiro você implementar um Route Middleware para atingir esse efeito.

Exemplo bem simplificado:

<?php

namespace App\Http\Middleware;

use Closure;
use App\Models\TodoList;

class UserOwnsTodoList
{
    public function handle($request, Closure $next)
    {
        $user_id = Auth::id();
        $list_id = $request->route()->list_id;
        $list = TodoList::find($list_id);

        if($list->user->id === $user_id) {
            return $next($request);
        } else {
            $message = 'Você não é dono dessa lista!';

        return redirect()
            ->route('error route')
            ->with(compact('message'));
        }
    }
}

Pra funcionar isso, vai depender de você ter feito:

  • uma relationship TodoList belongsTo User no TodoList Model
  • registrar esse middleware no kernel em protected $routeMiddleware
  • e também no routes/web algo assim: Route::middleware(['UserOwnsTodoList', 'outro middleware', 'etc']);

Extra: já previ que provavelmente você vai acabar reutilizando alguma query pra selecionar 1 ou várias listas desse User. Nesse caso sugiro um scope no model. Algo assim:

public function scopeMyLists($query, $user_id) {
    $query->whereHas('user', function($query) use ($user_id) {
        $query->where('user_id', '=', $user_id);
    });

    return $query;
}

E pra usar em qualquer lugar que chamar o model...

$my_lists = TodoList::myLists($user_id);

Opa Ricardo, beleza? Vamos por partes:

Eu consegui implementar a lógica do middleware, e aparentemente está funcionando :D só estou tendo um problema para renderizar a página de erro. Aparece o seguinte erro:

localhost redirected you too many times. Try clearing your cookies. ERR_TOO_MANY_REDIRECTS(já limpei os cookies)

O fluxo está sendo esse:

1- Usuário não é o dono daquela lista, então no middleware eu faço:

            return redirect()->route('todo_list.forbidden');
  1. Essa rota aponta para um método do TodoListController que simplesmente retorna uma view
Route::get('todo_list/forbidden', 'TodoListController@forbidden')->name('todo_list.forbidden');

 public function forbidden() {

        return view('todo_list.no-permission');
    }
}

Você tem alguma idéia do que possa ser?

Aqui está o commit que fiz realizando o que você me passou:

https://github.com/luandacosta/Laravel-TodoList/commit/a1bc41558b9aba1ba137969bb37f8efabfe44c7f

A parte extra eu não entendi muito bem.

solução!

Aqui você definiu um Route::resource e em seguida um route::get

https://github.com/luandacosta/Laravel-TodoList/blob/a1bc41558b9aba1ba137969bb37f8efabfe44c7f/routes/web.php

O middleware está afetando inclusive a rota do forbidden, gerando um loop infinito de redirect.

Uma solução talvez seja inverter a ordem dessas 2 linhas.

A parte do extra anota pq mais tarde você vai querer dar uma otimizada no código e deixá-lo mais enxuto (DRY, SOLID, design patterns etc). Me add no GitHub e te explico mais lá ricardoaugusto.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software