Autorização (CanCanCan) e RBAC
Autenticação prova quem você é; autorização decide o que você pode fazer — são coisas diferentes.
Devise (lição anterior) resolve autenticação: provar quem o usuário é. Isso não diz nada sobre o que ele pode fazer — um usuário comum autenticado não deveria poder deletar o pedido de outra pessoa só porque está logado. Essa segunda pergunta é autorização, e RBAC (Role-Based Access Control) é o modelo mais comum de resolver: cada usuário tem um papel (role), e o papel define o que é permitido.
CanCanCan — regras centralizadas numa Ability
class Ability
include CanCan::Ability
def initialize(usuario)
return unless usuario # visitante não autenticado não tem nenhuma permissão
if usuario.admin?
can :manage, :all # admin pode tudo, em qualquer recurso
else
can :read, Produto # qualquer usuário logado pode ler produtos
can [:create, :update], Pedido, usuario_id: usuario.id # só os PRÓPRIOS pedidos
cannot :destroy, Pedido # ninguém além de admin cancela pedido
end
end
endusuario_id: usuario.id é a parte que importa: a regra não é só "pode editar Pedido" — é "pode editar Pedido, desde que seja o dono dele". Isso é o que evita um usuário comum editar o pedido de outra pessoa só trocando o id na URL (o problema chamado IDOR).
Usando no controller
class PedidosController < ApplicationController
load_and_authorize_resource # carrega @pedido E checa a Ability automaticamente
def update
if @pedido.update(pedido_params)
render json: @pedido
else
render json: { errors: @pedido.errors.full_messages }, status: :unprocessable_entity
end
end
endSe a Ability recusar, o CanCanCan levanta CanCan::AccessDenied — que, tratado em ApplicationController (mesma ideia de rescue_from da lição de controllers), vira um 403 Forbidden na resposta, sem uma linha de if a mais dentro de cada action.
Exercício
Um papel novo, gerente, pode ler e atualizar qualquer Pedido (não só o próprio), mas não pode deletar nenhum. Adicione essa regra à Ability.