Download the PHP package gsebastiao/laravel-authz without Composer
On this page you can find all versions of the php package gsebastiao/laravel-authz. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download gsebastiao/laravel-authz
More information about gsebastiao/laravel-authz
Files in gsebastiao/laravel-authz
Package laravel-authz
Short Description Grupos e permissões (RBAC) para Laravel, simples de começar: cascata de prioridade, validade por data, multi-tenant, cache e auditoria opcionais.
License MIT
Informations about the package laravel-authz
Laravel Authz
Controle quem pode fazer o quê no seu sistema Laravel usando grupos e permissões.
- Coloque usuários em grupos ("Financeiro", "RH"...) e dê permissões aos grupos.
- Dê ou negue uma permissão a um usuário específico, quando precisar de uma exceção.
- Defina validade por data ("tem acesso só até 31/12").
- Funciona com
@can,Gate, Policies e middleware de rota do Laravel. - Multi-tenant, cache e auditoria são opcionais e começam desligados.
Índice
- Requisitos
- Instalação
- Primeiros passos (5 minutos)
- Onde checar permissões
- Como a decisão é tomada
- Referência rápida
- Recursos opcionais — catálogo no config, cache, multi-tenant, auditoria, nomes de tabela
- Problemas comuns
- Atualizando da versão 2.x
1. Requisitos
- PHP 8.2 ou superior
- Laravel 11, 12 ou 13
- Uma tabela de usuários (a
userspadrão do Laravel serve)
2. Instalação
Passo 1 — instale o pacote:
Passo 2 — rode o instalador:
Ele pergunta se você quer rodar o migrate. São criadas 5 tabelas:
auth_groups, auth_groups_users, auth_permissions,
auth_permissions_groups e auth_permissions_users.
O pacote traz as próprias migrations e o migrate as executa direto: nada é
copiado para o seu projeto, e a pasta database/migrations fica limpa. (Sem
o instalador, php artisan migrate faz o mesmo.)
Quer editar o config ou as migrations? Rode
php artisan authz:install --publish: ele copiaconfig/authz.phpe as migrations para o projeto, e você pode editá-los antes domigrate. Também dá para publicá-los separadamente, comphp artisan vendor:publish --tag=authz-configephp artisan vendor:publish --tag=authz-migrations. Se o projeto já tem uma cópia publicada, ela é a que vale.Sua tabela de usuários não se chama
users? Responda não quando o instalador perguntar, coloqueAUTHZ_TABLE_USER=sua_tabelano.env(ou ajustetables.usersemconfig/authz.php) e depois rodephp artisan migrate. Veja todas as variáveis em Configurar pelo.env.
Passo 3 — adicione o trait no model de usuário:
Pronto. O pacote já está funcionando.
3. Primeiros passos (5 minutos)
Vamos montar um exemplo real: o grupo Financeiro pode ver e aprovar pagamentos.
3.1 Declare as permissões
Em config/authz.php:
E rode:
Dica: use o formato
modulo.acao. O pacote separa o módulo (financeiro) e a ação (aprovar) sozinho. Rode este comando sempre que mudar a lista (ex: no deploy) — ele cria as novas, atualiza as alteradas e nunca apaga nada.
3.2 Crie o grupo e dê as permissões a ele
Num seeder, num php artisan tinker ou numa tela de administração:
3.3 Coloque um usuário no grupo
3.4 Cheque
É isso. Todo o resto do pacote são variações desses quatro passos.
4. Onde checar permissões
| Onde | Como |
|---|---|
| Rota | Route::get(...)->middleware('authz.permission:financeiro.ver') |
| Controller | Gate::authorize('financeiro.aprovar'); (erro 403 se não tiver) |
| Blade | @can('financeiro.aprovar') ... @endcan ou @hasPermission('financeiro.aprovar') ... @endHasPermission |
| Model / Service | $user->hasPermission('financeiro.aprovar') |
| Policy | return $user->hasPermission('financeiro.editar') && $fatura->user_id === $user->id; |
| Qualquer lugar | Authz::hasPermission('financeiro.aprovar') (usuário logado) |
Middleware de rota
Visitante não logado vai para a tela de login (401 em requisições JSON);
usuário logado sem permissão recebe erro 403. Ou seja: um 403 significa
sempre que o usuário está logado e a checagem deu false — nunca que ele
não está autenticado.
Nomes não diferenciam maiúsculas de minúsculas nem espaços em volta, tanto
para permissões como para grupos. Atenção à diferença entre os separadores:
| é "qualquer uma destas" e , é "todas estas" — trocar um pelo outro é a
causa mais comum de um 403 inesperado.
Blade
As diretivas nativas @can / @cannot também funcionam.
Gate e @can
O pacote se liga ao Gate do Laravel automaticamente. Suas Policies e
Gate::define() sempre têm prioridade — o pacote só responde quando nenhuma
regra do seu projeto respondeu. Isso também significa que um "super admin"
via Gate::before continua funcionando:
5. Como a decisão é tomada
Um usuário recebe permissões de dois lugares: dos grupos dele e de exceções individuais (regras só para ele). Quando as regras se contradizem, vence a primeira linha desta tabela que se aplicar:
| # | Situação | Resultado |
|---|---|---|
| 1 | Exceção individual negando | ❌ Negado — nada reverte isso |
| 2 | Exceção individual concedendo | ✅ Concedido |
| 3 | Algum grupo nega de forma absoluta | ❌ Negado |
| 4 | Algum grupo concede | ✅ Concedido |
| 5 | Só há negações comuns de grupo | ❌ Negado |
| 6 | Nenhuma regra | ❌ Negado |
Na prática: se ninguém disse nada sobre o usuário, os grupos decidem. Se nenhum grupo disser nada, a resposta é "não".
Negação comum x absoluta. Uma negação comum de grupo perde para a concessão de outro grupo. Uma negação absoluta vence qualquer grupo — use para regras de compliance ("estagiário nunca aprova pagamento, mesmo que esteja em outro grupo que aprova"):
Só contam regras vigentes. Uma regra é ignorada se estiver apagada, se a
start_date ainda não chegou, se a end_date já passou, se o grupo ou a
membresia estiver com status = 0, ou se a permissão estiver desativada.
6. Referência rápida
Permissões e grupos podem ser passados pelo nome ('financeiro.aprovar',
'Financeiro') ou pelo id (7). Nomes de permissão não diferenciam
maiúsculas de minúsculas.
No model User (trait HasAuthz)
| Método | O que faz |
|---|---|
hasPermission($p) |
Tem a permissão? |
hasAnyPermission([...]) / hasAllPermissions([...]) |
Tem alguma / todas? |
getPermissionNames() / getPermissionIds() |
Lista das permissões efetivas |
grantPermission($p, $opcoes = []) |
Dá a permissão só para este usuário |
denyPermission($p, $opcoes = []) |
Nega a permissão só para este usuário (vence os grupos) |
revokePermission($p) |
Retira o que foi dado com grantPermission |
clearPermissionOverride($p) |
Retira qualquer regra individual (concessão ou negação) |
syncPermissions([...]) |
Deixa as concessões individuais iguais à lista |
hasRole($g) / hasAnyRole([...]) / hasAllRoles([...]) |
Está no grupo? |
assignRole($g, $opcoes = []) / assignRoles([...]) |
Coloca no grupo (não duplica) |
removeRole($g) |
Tira do grupo |
syncRoles([...]) |
Deixa o usuário exatamente nos grupos da lista |
getRoleNames() / getRoleIds() / getGroups() |
Grupos atuais |
setPrimaryRole($g) / getPrimaryRole() |
Grupo principal |
User::getUsersWithRole($g) |
Todos os usuários de um grupo |
User::whereHasPermission($p) |
Query de usuários com a permissão (sem N+1) |
Prefere separar?
HasRoleseHasPermissionstambém existem e podem ser usados juntos.HasAuthzé só os dois combinados.
No Facade Authz (gerenciar dados)
| Assunto | Métodos |
|---|---|
| Grupos | createGroup($nome, $descricao = null), updateGroup($id, [...]), deleteGroup($id), restoreGroup($id) |
| Membros | addUserToGroup($userId, $groupId, [...]), updateGroupMembership($id, [...]), removeUserFromGroup($id) |
| Permissões | createPermission($nome, $modulo, $acao, $rotulo), updatePermission($id, [...]), deletePermission($id), restorePermission($id) |
| Regras de grupo | grantPermissionToGroup($groupId, $permId, [...]), updateGroupPermission($id, [...]), revokeGroupPermission($id) |
| Regras individuais | grantPermissionToUser($userId, $permId, [...]), updateUserPermission($id, [...]), revokeUserPermission($id) |
| Consultas | hasPermission, hasRole, getEffectivePermissions, getUserGroups, getAssignablePermissions |
| Nome → id | resolvePermissionId('financeiro.aprovar'), resolveGroupId('Financeiro') |
| Cache | forgetUserCache($userId), flushCache() |
Comportamentos importantes:
- *`delete
fazem soft delete** (dá para recuperar comrestore*). Passepurge: truepara apagar de vez:Authz::deleteGroup($id, purge: true)`. - *`grant
eaddUserToGroup` não duplicam.** Se a regra ou membresia já existir, ela é atualizada com as opções informadas. - *`update
só aceitam campos conhecidos.** Um campo inválido gera um erro que lista os campos aceitos. Retornamfalse` quando nada mudou. - Erros de uso (id inexistente, nome duplicado, campo inválido) lançam
Gsebastiao\LaravelAuthz\Exceptions\AuthzExceptioncom uma mensagem que explica o que fazer. - Toda escrita roda dentro de uma transação e dispara um evento do Laravel
(
GroupCreated,UserAddedToGroup,PermissionGrantedToGroup... — vejasrc/Events).
Opções aceitas
| Onde | Campos |
|---|---|
| Grupo | name, description, status |
Membresia (assignRole, addUserToGroup) |
status, start_date, end_date, is_primary, observacao |
| Permissão | permission, module, action, label, description, order, status, tenant_id |
| Regra de grupo | is_granted, is_absolute, start_date, end_date |
| Regra individual | is_granted, start_date, end_date |
Funções globais
Também existem atalhos globais, úteis em qualquer lugar: authz(),
hasPermission(), hasAnyPermission(), hasAllPermissions(), hasRole(),
hasAnyRole(), hasAllRoles(), getUserGroups(), getUserPermissions().
Sem $userId, usam o usuário logado.
7. Recursos opcionais
Nada desta seção é necessário para usar o pacote.
Configurar pelo .env (sem editar o config)
O pacote carrega a sua configuração sozinho: não é preciso manter nem editar
config/authz.php para mudar as opções abaixo. Ponha no .env só o que
quiser mudar:
| Variável | Padrão | Para quê |
|---|---|---|
AUTHZ_TABLE_GROUP |
auth_groups |
Tabela dos grupos |
AUTHZ_TABLE_GROUP_USER |
auth_groups_users |
Tabela grupo ↔ usuário |
AUTHZ_TABLE_AUTH_PERMISSION |
auth_permissions |
Tabela das permissões |
AUTHZ_TABLE_AUTH_PERMISSION_USER |
auth_permissions_users |
Tabela permissão ↔ usuário |
AUTHZ_TABLE_AUTH_PERMISSION_GROUP |
auth_permissions_groups |
Tabela permissão ↔ grupo |
AUTHZ_TABLE_USER |
users |
Tabela de usuários do seu projeto |
AUTHZ_USER_MODEL |
(não definir) | Model de usuário; sem valor, o de config/auth.php |
AUTHZ_GATES |
true |
@can, Gate e can: passam a entender as permissões do pacote |
AUTHZ_CACHE_ENABLED |
false |
Liga o cache (recomendado em produção) |
AUTHZ_CACHE_STORE |
(não definir) | Store de cache; sem valor, o padrão do projeto |
AUTHZ_CACHE_TTL |
3600 |
Validade do cache, em segundos |
AUTHZ_CACHE_PREFIX |
authz |
Prefixo das chaves do cache |
AUTHZ_CACHE_INVALIDATE_ON_WRITE |
true |
Limpa o cache sozinho quando o pacote grava |
AUTHZ_TENANT_CONTEXT |
Gsebastiao\LaravelAuthz\Support\NullTenantContext |
Classe do multi-tenant |
AUTHZ_AUDIT_ENABLED |
false |
Liga a auditoria |
AUTHZ_AUDIT_COLUMN_PREFIX |
audit_ |
Prefixo das colunas de applyAuditJoins() |
AUTHZ_AUDIT_JOIN_EVENT |
created,updated,deleted |
Eventos usados por applyAuditJoins(), separados por vírgulas |
AUTHZ_AUDIT_LABEL_COLUMN_GROUP |
name |
Coluna com o nome legível do grupo na auditoria |
AUTHZ_AUDIT_LABEL_COLUMN_PERMISSION |
permission |
Coluna com o nome legível da permissão na auditoria |
Não deixe uma variável em branco (
AUTHZ_CACHE_STORE=): o Laravel lê isso como texto vazio, não como "sem valor". Para voltar ao padrão, apague a linha. Comphp artisan config:cache, rode-o de novo depois de mudar o.env.
Só o catálogo de permissões (permissions, uma lista) precisa do arquivo
config/authz.php — veja abaixo. Se não usar o catálogo, o arquivo é opcional.
Catálogo completo no config
Além da forma curta, cada permissão aceita mais detalhes:
Para montar uma tela de "gerenciar permissões", use
Authz::getAssignablePermissions().
Cache
Por padrão cada checagem consulta o banco. Em produção, ligue o cache no .env:
Tudo o que é feito pelos métodos do pacote atualiza o cache sozinho. Se você
alterar as tabelas direto no banco (SQL, seeder com DB::table), rode:
Outras opções (AUTHZ_CACHE_STORE, AUTHZ_CACHE_TTL...) estão na
tabela do .env. Validades por data são reavaliadas quando o TTL expira
(padrão: 1 hora).
Multi-tenant (empresas, filiais, sedes...)
Use só se o sistema for dividido em partes que não podem ver os grupos umas das outras. Crie uma classe que diga qual é o tenant atual:
E aponte para ela no .env:
(ou, se preferir, em config/authz.php:
'tenant_context' => \App\Support\TenantAtual::class.)
O que muda:
- Grupos passam a pertencer a um tenant. Pode existir um "Financeiro" em
cada empresa, cada um com suas permissões.
createGroup()usa o tenant atual. Um grupo comtenant_idNULL é global: vale em todos os tenants (é o caso dos grupos criados antes de você ligar o multi-tenant). Grupos de outro tenant continuam invisíveis. - Permissões continuam globais, a não ser que você crie uma exclusiva:
Authz::createPermission('exportar.massa', 'relatorios', 'exportar', 'Exportar', tenantId: 3). Permissões exclusivas ficam invisíveis e sem efeito nos outros tenants, e não podem ser dadas a grupos de outro tenant. - Nomes de grupo (
assignRole('Financeiro')) são procurados entre os grupos do tenant atual e os globais. Se existirem dois com o mesmo nome (um global e um do tenant), o pacote avisa e pede o id em vez de escolher por você.
Atenção: o id do tenant nunca pode ser
0nem string vazia.Os métodos de gerenciamento não verificam se o id que você passou pertence ao tenant atual. Numa tela de administração por tenant, valide isso no seu controller antes de chamar
updateGroup,deleteGroupetc.
Auditoria
Com o pacote gsebastiao/laravel-auditable instalado e
AUTHZ_AUDIT_ENABLED=true, toda alteração feita pelo pacote é auditada.
Sem o pacote de auditoria, tudo funciona normalmente, apenas sem registrar.
Nomes de tabela diferentes
Use as variáveis AUTHZ_TABLE_* no .env (ou edite tables em
config/authz.php) antes de rodar o migrate. Mudar depois não renomeia
tabelas já criadas.
8. Problemas comuns
Grupo 'X' não encontrado — confira o nome (maiúsculas e espaços em volta
não importam). Com multi-tenant, o grupo precisa ser do tenant atual ou global.
Permissão 'x' não encontrada — rode php artisan authz:sync-permissions
depois de declarar a permissão no config.
Dei a permissão mas hasPermission continua false (ou a rota dá 403).
Verifique, nesta ordem:
- O usuário tem uma negação individual? (
denyPermissionvence tudo) - Algum grupo dele tem negação absoluta para essa permissão?
- A regra, o grupo ou a membresia está com
status = 0,start_dateno futuro ouend_dateno passado? - A permissão está desativada ou é exclusiva de outro tenant?
- Cache ligado e você alterou o banco direto? Rode
php artisan authz:cache-reset. - Na rota, você usou
,(exige TODAS) onde queria|(basta UMA)?
Para ver o que o pacote enxerga do usuário:
Se a permissão aparece nessa segunda lista mas a rota continua a dar 403, o problema está na rota (item 6), não nos dados.
@can('financeiro.aprovar') retorna false mesmo com a permissão. Veja
se o seu projeto tem um Gate::define('financeiro.aprovar', ...) ou uma
Policy respondendo antes — eles têm prioridade. Confirme também que
gates.auto_register está true em config/authz.php.
Já existe um grupo apagado com o nome... — nomes são únicos mesmo depois
do soft delete. Use Authz::restoreGroup($id) (ou restorePermission) como a
mensagem indica.
Rodei vendor:publish duas vezes. Sem problema: migrations já publicadas
não são duplicadas.
migrate diz que a tabela já existe. Não deve acontecer: as migrations do
pacote ignoram tabelas que já existem. Se acontecer com um nome de tabela
diferente, confira as variáveis AUTHZ_TABLE_* do .env.
9. Atualizando da versão 2.x
A 2.x não conseguia ser instalada numa aplicação nova (o migrate falhava e as
migrations não eram publicadas corretamente). Se você contornou isso
manualmente e já tem as tabelas:
- Não publique as migrations de novo — as tabelas não mudaram. (Se rodar
php artisan migrate, as migrations do pacote ignoram as tabelas que já existem.) - Se usava
HasRoleseHasPermissionsjuntos, agora funciona; ou troque os dois porHasAuthz. - Revise o CHANGELOG — algumas regras passaram a ser
aplicadas como sempre foram documentadas (grupo inativo e
start_datefutura deixam de conceder, por exemplo). - Opcional: nas instalações novas, apagar um usuário apaga as membresias dele
em cascata. Se quiser o mesmo numa instalação antiga, troque a foreign key
auth_groups_users.user_idparaON DELETE CASCADEnuma migration sua.
Testes
A suíte (85 testes) roda com SQLite em memória e cobre a cascata de decisão, datas de validade, tenant, cache, auditoria, os traits do model, Gate, middlewares, Blade e os comandos artisan. Validada em Laravel 11, 12 e 13.
Licença
MIT
All versions of laravel-authz with dependencies
illuminate/support Version ^11.0|^12.0|^13.0
illuminate/database Version ^11.0|^12.0|^13.0