Acapadev

Acapadev SDK

Cargos e Permissões (Roles)

Para garantires que os utilizadores da tua aplicação satélite herdam os cargos estipulados centralmente no Acapadev ID, o SDK oferece uma Trait muito conveniente: HasAcapadevRoles.

Requer o SDK v1.2.1 ou superior

Em versões anteriores a leitura de cargos estava partida e devolvia sempre uma lista vazia, em silêncio — o SDK chamava um host que não existe. Se a tua aplicação usa cargos, corre composer update devkussema/acapadev-sdk antes de continuares. Não é preciso mexer no .env.

Como Configurar

Abre o modelo User da tua aplicação (geralmente app/Models/User.php) e adiciona a Trait:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Acapadev\Sdk\Traits\HasAcapadevRoles;

class User extends Authenticatable
{
    use HasAcapadevRoles;

    // ...
}

O Identificador do Utilizador

A API responde sobre o utilizador no Acapadev ID, que raramente tem o mesmo ID que o utilizador na tua base de dados local. Se guardares o ID central numa coluna acapadev_id, o SDK usa-a automaticamente:

Schema::table('users', function (Blueprint $table) {
    $table->unsignedBigInteger('acapadev_id')->nullable()->index();
});

E preenche-la no callback do SSO (ver Socialite SSO). Se guardares esse ID noutra coluna, sobrepõe o método no teu modelo:

public function getAcapadevIdentifier(): int|string
{
    return $this->sso_user_id;
}

Sem nenhuma destas coisas, o SDK recorre à chave primária local — o que só funciona se os dois IDs coincidirem por acaso. É a causa número um de continuares a receber listas vazias para utilizadores que sabes terem cargos atribuídos.

Como Usar

A Trait adiciona métodos poderosos ao teu utilizador. Ela comunica com o Acapadev ID de forma invisível (via Facade Acapadev) e guarda o resultado em cache durante 5 minutos (300 segundos) para otimizar o desempenho.

// Obter um array com todos os cargos do utilizador na central
$cargos = $user->getAcapadevRoles();

// Verificar se o utilizador tem um cargo específico
if ($user->hasAcapadevRole('admin_financeiro')) {
    // Permitir acesso
}

// Verificar se tem pelo menos um de vários cargos
if ($user->hasAnyAcapadevRole(['admin', 'gestor'])) {
    // Permitir acesso
}

// Limpar a cache manualmente (por exemplo, quando recebes um Webhook de atualização)
$user->clearAcapadevRolesCache();

Métodos Disponíveis

MétodoDescrição
getAcapadevRoles(): arrayDevolve todos os cargos do utilizador (cache configurável, 5 min por omissão); array vazio em caso de erro na API, com aviso no log
getAcapadevIdentifier(): int|stringO ID do utilizador no Acapadev ID. Usa acapadev_id se existir; sobrepõe-o se guardares o ID noutra coluna
hasAcapadevRole(string $role): boolVerifica se o utilizador possui um cargo específico
hasAnyAcapadevRole(array $roles): boolVerifica se o utilizador possui pelo menos um dos cargos indicados
clearAcapadevRolesCache(): voidLimpa a cache de cargos deste utilizador

Invalida a Cache Quando Receberes Webhooks de Atualização

Quando o evento WebhookReceived chegar com $event->event === 'role.updated' (ou equivalente), chama $user->clearAcapadevRolesCache() para garantir que a próxima verificação de cargo reflete o estado mais recente, em vez de esperar 5 minutos pela expiração natural da cache.

O Formato da Resposta

O contrato de GET /v1/users/{id}/roles é uma lista de nomes de cargos, em texto:

{
  "status": "success",
  "user_id": 3,
  "app_id": 21,
  "data": ["auditor", "gestor"]
}

O que podes assumir com segurança:

  • data é sempre uma lista, mesmo com zero ou um cargo.
  • [] é uma resposta legítima — «este utilizador não tem cargos nesta app». Não é um erro.
  • Pode trazer vários elementos. Um utilizador pode ter mais do que um cargo na mesma app — não assumas data[0].
  • A ordem é alfabética e estável entre chamadas iguais.
  • Só vêm os cargos da app que pergunta. Uma app nunca vê os cargos de um utilizador noutra app.

O SDK normaliza isto por ti: getAcapadevRoles() devolve sempre array<int, string>. Se a API alguma vez responder com objetos ([{"name": "gestor"}]), o SDK extrai o name e continua a funcionar. O que não conseguir interpretar é descartado com um aviso no log, nunca em silêncio.

Comportamento em Caso de Falha

Se a API central estiver indisponível, getAcapadevRoles() devolve um array vazio em vez de lançar uma exceção — a Trait falha de forma segura (fail-safe), assumindo que o utilizador não tem cargos especiais em vez de bloquear a aplicação.

A partir da v1.2.1 isso deixa rasto: é registado um warning com o código de estado e o ID consultado, e o insucesso é guardado em cache curta (10 s) para que uma API em baixo não custe uma chamada falhada — e o respetivo timeout — em cada pedido.

Se precisares de distinguir «este utilizador não tem cargos» de «não consegui perguntar», usa a versão que propaga o erro:

use Acapadev\Sdk\Exceptions\AcapadevApiException;
use Acapadev\Sdk\Facades\Acapadev;

try {
    $cargos = Acapadev::fetchUserRoles($user->acapadev_id);
} catch (AcapadevApiException $e) {
    // decide tu: 503, tentar de novo, usar um valor local de recurso...
}

Cuidado com o Curto-Circuito do ||

Num padrão como $this->role === 'admin' || $this->hasAcapadevRole('admin'), o || pára no primeiro true. Como as contas de administração costumam ter o cargo definido localmente, nunca chegam a consultar a API — e uma integração partida só se manifesta para utilizadores normais, precisamente aqueles cujos cargos o SSO deveria determinar. Testa sempre com uma conta que não seja administradora localmente.

Enter para selecionar ESC para sair