No desenvolvimento de ecossistemas distribuídos, a estratégia de autenticação e a estruturação das camadas de acesso são cruciais para a escalabilidade e segurança. Uma abordagem moderna para lidar com a diversidade de clientes (web, mobile, dispositivos IoT) é o padrão BFF (Backends For Frontends).
O Papel do BFF na Autenticação de Microserviços
O BFF atua como uma camada intermediária adaptada para necessidades específicas de cada interface de usuário. Em vez de o cliente consumir múltiplos microserviços diretamente, ele interage com um ponto único que orquestra as chamadas internas.
Esta arquitetura traz benefícios claros:
- Redução de latência: O cliente realiza apenas uma requisição HTTP externa, e o BFF consolida os dados de diversos serviços em uma única resposta.
- Segurança simlpificada: Módulos de autenticação e autorização podem ser centralizados no BFF. Como cada BFF é dedicado a um tipo de cliente (ex: App do Motorista), as permissões não se misturam com as de outros perfis (ex: App do Passageiro).
Segurança com Sa-Token
Para gerenciar a segurança de forma eficiente em Java, o Sa-Token surge como uma alternativa leve e poderosa frente ao Spring Security ou Shiro. Ele simplifica processos complexos como login multi-terminal, controle de sessões distribuídas e integração com gateways.
Dentre suas funcionalidades, destacam-se:
- Autenticação Multi-nível: Suporte a logins simultâneos ou exclusivos por dispositivo.
- Gestão de Sessão: Integração nativa com Redis para persistência de tokens em ambientes de microserviços.
- Controle de Acesso: Anotações simples parra verificação de permissões e papéis (roles).
Persistência de Dados e Mapeamento com MyBatis
Na camada de persistência, a utilização de SQL dinâmico permite flexibilidade no gerenciamento das entidades de negócio. Abaixo, exploramos a implementação de consultas e inserções para o módulo de motoristas.
Verificação de Existência de Registro
Para evitar duplicidade, é comum verificar se um motorista já existe na base através do open_id ou do identificador interno. Note o uso do tipo long para garantir que o retorno nunca seja nulo.
<select id="checarMotoristaExistente" parameterType="Map" resultType="long">
SELECT COUNT(id_interno) AS total
FROM tabela_motorista
WHERE 1=1
<if test="idVinculo != null">
AND vinculo_externo = #{idVinculo}
</if>
<if test="idMotorista != null">
AND id_interno = #{idMotorista}
</if>
</select>
A interface DAO correspondente utilizaria um Map para facilitar a conversão de objetos complexos (DTOs) em parâmetros SQL através de bibliotecas de utilitários como o Hutool (BeanUtil.beanToMap).
Cadastro de Novo Perfil
Ao registrar um novo motorista, definimos estados iniciais e estruturas JSON para metadados de desempenho e níveis de serviço. É importante observar o uso de crases em campos que podem ser palavras reservadas do banco de dados, como status.
<insert id="inserirNovoMotorista" parameterType="Map">
INSERT INTO tabela_motorista
SET vinculo_externo = #{idVinculo},
nome_exibicao = #{apelido},
url_foto = #{fotoUrl},
autenticado = 1,
metadados_resumo = '{"nivel": 0, "corridas_totais": 0, "avaliacao_semanal": 0}',
info_arquivada = false,
`status` = 1,
data_criacao = NOW()
</insert>
Estrutura da Tabela de Motoristas
O esquema abaixo detalha os campos necessários para suportar as operações de um sistema de transporte, incluindo informações de documentos e configurações de geolocalização.
CREATE TABLE tabela_motorista (
id_interno SERIAL PRIMARY KEY,
vinculo_externo VARCHAR(255) NOT NULL UNIQUE,
nome_exibicao VARCHAR(100),
documento_identidade VARCHAR(20),
telefone_contato CHAR(11),
status_autenticacao TINYINT DEFAULT 1, -- 1: Pendente, 2: Aprovado, 3: Rejeitado
foto_perfil_url VARCHAR(500),
config_viagem JSON, -- Armazena preferências como 'aceite automático'
metadados_resumo JSON,
`status` TINYINT NOT NULL, -- 1: Ativo, 2: Suspenso
data_criacao DATETIME NOT NULL
);
Gestão Financeira: Carteira do Motorista
Cada motorista possui uma carteira vinculada para gerir saldos de corridas e bônus do sistema. A inserção inicial garante a integridade referencial com a tabela principal.
<insert id="inicializarCarteira" parameterType="com.exemplo.projeto.pojo.EntidadeCarteira">
INSERT INTO tabela_carteira
(id_motorista, saldo_atual, senha_pagamento)
VALUES
(#{idMotorista}, #{saldoInicial}, #{hashSenha})
</insert>
As configurações de preferência do motorista são frequentemente armazenadas em formato JSON para permitir flexibilidade sem a necessidade de alterações constantes no esquema da tabela. Um exemplo de configuração de escuta de pedidos incluiria:
{
"aceiteAuto": 0,
"modoServico": true,
"raioBuscaKm": 3.5,
"distanciaMinimaPedido": 0
}