DevPath · Aprenda a programar ESPTEN

Autenticação e segurança

Autorização: exigir token e verificar papéis

Autorizar é responder "você pode fazer isto?"

A autenticação diz quem você é; a autorização decide o que você tem permissão de fazer. São dois passos distintos, e eles se refletem em dois códigos de status:

Um erro muito comum é devolver 401 quando na verdade cabe 403. Se o usuário já está autenticado e simplesmente lhe falta a permissão, é 403.

Middleware que exige um token válido

O primeiro middleware lê o cabeçalho Authorization. Se faltar —ou se o token não for válido porque a assinatura não bate— ele corta com 401. Se for válido, guarda o usuário em req.usuario para que os passos seguintes saibam quem é.

function requerAuth(req, res, next) {
  const cabecalho = req.headers.authorization;
  // verificarToken devolve o payload, ou null se a assinatura não bater.
  const usuario = cabecalho ? verificarToken(cabecalho, SEGREDO) : null;
  if (!usuario) {
    res.status(401).json({ error: "Não autorizado" });
    return; // corta: não chama next()
  }
  req.usuario = usuario;
  next();
}

Num caso real, o cabeçalho é "Bearer <token>": separa-se o esquema (Bearer) do token antes de verificá-lo. Para os exercícios vamos mandar o token diretamente no cabeçalho para focar na lógica.

Middleware de papéis

A autorização por papel se resolve com uma fábrica de middleware: uma função que recebe o papel exigido e devolve o middleware concreto. Assim você pode escrever requerPapel("admin") em qualquer rota.

function requerPapel(papel) {
  return function (req, res, next) {
    if (!req.usuario || req.usuario.papel !== papel) {
      res.status(403).json({ error: "Sem permissão" });
      return;
    }
    next();
  };
}

Eles são encadeados em ordem: primeiro requerAuth (para que exista req.usuario), depois requerPapel("admin"):

app.delete("/usuarios/:id", requerAuth, requerPapel("admin"), removerUsuario);

Exemplos

Encadear autenticação e papel

function requerPapel(papel) {
  return function (req, res, next) {
    if (!req.usuario || req.usuario.papel !== papel) {
      res.status(403).json({ error: "Sem permissão" });
      return;
    }
    next();
  };
}

const soAdmin = requerPapel("admin");
const req = { usuario: { papel: "leitor" } };
const res = {
  status(c) { this.code = c; return this; },
  json(b) { console.log(this.code, JSON.stringify(b)); },
};
soAdmin(req, res, () => console.log("acesso concedido"));
Coloque isto em prática

O DevPath é um curso prático: aqui você lê a teoria; no app você a coloca em prática com exercícios que rodam de verdade, offline.

Comece grátis no app →
← Autenticação: senhas e tokensSegurança web: OWASP, CORS e boas práticas →