Aprenda / Ruby on Rails

FundamentosAula 9 de 2016 min0% da trilha

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

app/models/ability.rb
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
end

usuario_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

app/controllers/pedidos_controller.rb
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
end

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

Quiz rápido

Qual a diferença entre autenticação e autorização?
O que a condição usuario_id: usuario.id numa regra can :update, Pedido garante?