Firebase Realtime Database: Como Regras de Segurança (quase) travaram meu projeto de Jogo da Velha
Você já teve aquela sensação de que o código está certo, mas simplesmente não funciona? Foi o que vivi no desenvolvimento de um projeto pessoal usando o Firebase Realtime Database. O jogo da velha multiplayer estava no ar, mas a partida nunca começava. 😵💫
A causa? Regras de segurança mal compreendidas.
Neste artigo compartilho o erro, a descoberta, a solução e um lembrete: “Não é sobre o jogo. É sobre quebrar padrões.”
🔍 O problema
Ao testar o projeto, percebi que os jogadores se conectavam, mas a partida não iniciava. Após diversas revisões no código, identifiquei que o Firebase estava negando a alteração da chave isFull
, impedindo que o jogo começasse.
O motivo era claro (depois que eu entendi): as regras de segurança estavam mal configuradas e esperavam uma estrutura de dados que nem existia no meu banco.
🛠️ A estrutura esperada no banco de dados
O Firebase aguardava que os dados dos jogadores estivessem registrados em uma estrutura chamada userGames
, mas essa parte nunca foi implementada. Por isso, as permissões eram negadas.
A estrutura real do banco no projeto era assim:
games
└── game
└── $matchId
├── players
│ ├── player1
│ └── player2
├── isFull
├── currentPlayer
├── eventos
└── moves
🔐 A Regra de Segurança que me travou
As regras originais tentavam validar algo assim:
"players": {
"player1": {
".write": "root.child('userGames/' + auth.uid + '/' + $matchId + '/playerId').val() === data.child('id').val() || !data.exists()"
},
"player2": {
".write": "root.child('userGames/' + auth.uid + '/' + $matchId + '/playerId').val() === data.child('id').val() || !data.exists()"
}
}
Ou seja, a permissão era baseada em uma verificação que sempre falhava, pois userGames
não existia.
✅ A correção que funcionou
Depois de estudar a documentação oficial do Firebase, reestruturei as regras com base na presença dos jogadores dentro da própria estrutura do jogo:
"players": {
"player1": {
".write": "!data.exists()"
},
"player2": {
".write": "!data.exists() && root.child('games/game' + $matchId + '/players/player1').exists()"
}
},
"isFull": {
".read": "auth != null",
".write": "!data.exists() || (root.child('games/game' + $matchId + '/players/player1').exists() && root.child('games/game' + $matchId + '/players/player2').exists())"
}
Agora sim! O jogo reconhece a presença dos dois jogadores e altera a chave isFull
para true
, permitindo o início da partida. 🎮
📚 O que aprendi com isso?
- Não subestime a documentação.
- Regras de segurança são parte essencial do backend.
- Estude a ferramenta antes de usá-la.
- E o mais importante: “Imperfeito feito vence, perfeito nunca feito.”
Esse projeto é parte de uma série que estou escrevendo para documentar como estou quebrando padrões de procrastinação e evoluindo como dev.
Se você também está enfrentando desafios nos seus projetos, saiba que você não está sozinho.
---