Autenticação Sem Restrições
Nesta modalidade de autenticação, a interface completa da aplicação é disponibilizada ao cliente. Qualquer restrição visual ou de regra de negócio ocorre em conformidade com as configurações predefinidas para os diferentes perfis de usuários. O fluxo operacional assemelha-se ao cenário em que o próprio usuário insere a URL da aplicação no navegador e utiliza o formulário de login convencional.
Contrato de Integração de Relatórios do Servidor de Relatórios (Lado Servidor)
Objetivo
Este documento descreve o contrato de integração determinístico usado por sistemas externos para autenticar um usuário mapeado e abrir o ReportServer.
Não confundir: ExternalAuth x ReportIntegration
Este contrato cobre apenas o fluxo app-app de bootstrap de integração.
- ReportIntegration (este documento): autenticação entre sistemas via API key + token temporário de integração.
- ExternalAuth: autenticação de credenciais do usuário (username/senha) no login direto do ReportServer.
Importante:
- No endpoint /api/integration/bootstrap-report-session, não há validação de senha do usuário.
- A validação do bootstrap usa ReportIntegration:RequestApiKey* e BootstrapTokenSigningKey.
Resumo do Fluxo
- O sistema cliente envia uma requisição de bootstrap server-to-server.
- O ReportServer valida a chave de integração compartilhada e o payload da requisição.
- O ReportServer gera um token assinado, de curta duração e uso único.
- O ReportServer retorna uma URL de abertura contendo o token.
- O navegador abre /integration/entry com token e returnUrl opcional.
- IntegrationEntry consome o token, autentica o usuário mapeado e redireciona para o ReportServer completo.
- O usuário continua usando os recursos padrão de relatório, já protegidos por papéis e permissões do ReportServer.
Endpoint de Bootstrap
- Método: POST
- Rota: /api/integration/bootstrap-report-session
- Content-Type: application/json
Header obrigatório
- O nome do header é configurável por ReportIntegration:RequestApiKeyHeaderName.
- Nome de header padrão configurado: X-Report-Integration-Key.
- O valor do header deve corresponder a ReportIntegration:RequestApiKey.
- Essa chave é um segredo compartilhado entre o AdhocReport e o servidor de autorização do cliente.
Corpo da Requisição
{
"externalUserId": "external-user-id",
"clientSystemId": "client-system-id",
"returnUrl": "/optional-relative-return"
}
Regras dos campos
- externalUserId: obrigatório, deve mapear para um usuário existente no ReportServer (ApplicationUser.ExternalUserId).
- clientSystemId: obrigatório, identifica o sistema chamador.
- returnUrl: opcional, quando informado deve ser um caminho relativo iniciando com /.
Resposta de Sucesso
HTTP 200 OK
{
"success": true,
"message": "ok",
"launchUrl": "https://server/integration/entry?token=...",
"expiresAtUtc": "2026-06-02T18:30:00Z",
"reference": "trace-or-correlation-id"
}
Respostas de Erro
- 400 BadRequest
- invalid-request
- invalid-bootstrap-payload
- invalid-return-url
- 401 Unauthorized
- invalid-integration-key
- 403 Forbidden
- report-integration-disabled
- 404 NotFound
- external-user-not-found
- 500 InternalServerError
- report-integration-misconfigured
Todos os payloads de erro seguem:
{
"success": false,
"message": "error-code",
"launchUrl": null,
"expiresAtUtc": null,
"reference": "trace-or-correlation-id"
}
Comportamento do Token
- O payload do token contém:
- externalUserId
- clientSystemId
- tokenId
- issuedAtUtc
- expiresAtUtc
- Algoritmo de assinatura: HMACSHA256 com ReportIntegration:BootstrapTokenSigningKey.
- O token é de curta duração (BootstrapTokenLifetimeSeconds).
- O token é de uso único (replay é bloqueado com cache em memória).
- Falhas de validação incluem:
- missing-token
- invalid-token-format
- invalid-token-signature
- invalid-token-payload
- expired-token
- token-already-used
- report-integration-misconfigured
Configuração Obrigatória
Em appsettings / ambiente:
- ReportIntegration:Enabled
- ReportIntegration:RequestApiKeyHeaderName
- ReportIntegration:RequestApiKey
- ReportIntegration:BootstrapTokenLifetimeSeconds
- ReportIntegration:BootstrapTokenSigningKey
- ReportIntegration:IntegrationReportsRoute
Configuração típica (desenvolvimento):
"ReportIntegration": {
"Enabled": true,
"RequestApiKeyHeaderName": "X-Report-Integration-Key",
"RequestApiKey": "dev-report-integration-key",
"BootstrapTokenLifetimeSeconds": 120,
"BootstrapTokenSigningKey": "dev-bootstrap-signing-key-change-in-production",
"IntegrationReportsRoute": "/integration/entry",
"Cors": {
"AllowedOrigins": [
"https://localhost:7227",
"http://localhost:5148"
]
}
}
Observações:
- BootstrapTokenSigningKey é lida de configuração. Se ausente, o sistema falha com report-integration-misconfigured.
- Cors.AllowedOrigins é necessário quando o cliente chama o bootstrap em contexto cross-origin.
Notas de Segurança
- Não exponha a chave compartilhada nem a chave de assinatura em código client-side.
- Mantenha BootstrapTokenSigningKey obrigatório; não use valores de fallback hardcoded.
- Mantenha todas as chamadas em HTTPS.
- Use o reference da resposta para correlacionar erros visíveis ao usuário com logs do servidor.
Integração Mínima do Cliente (Guia Enxuto)
O cliente externo só precisa de duas ações:
- Chamar o endpoint de bootstrap (server-to-server).
- Abrir a launchUrl retornada no navegador.
O ReportIntegration.BlazorTestClient é um app de diagnóstico e não é obrigatório para integração de produção do cliente.
Exemplo cURL
curl -X POST "https://localhost:7019/api/integration/bootstrap-report-session" \
-H "Content-Type: application/json" \
-H "X-Report-Integration-Key: dev-report-integration-key" \
-d '{"externalUserId":"ext-usr-001","clientSystemId":"client-system-demo","returnUrl":"/"}'
Exemplo JavaScript
const response = await fetch("https://localhost:7019/api/integration/bootstrap-report-session", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Report-Integration-Key": "dev-report-integration-key"
},
body: JSON.stringify({
externalUserId: "ext-usr-001",
clientSystemId: "client-system-demo",
returnUrl: "/"
})
});
const payload = await response.json();
if (payload.success && payload.launchUrl) {
window.open(payload.launchUrl, "_blank");
}
Exemplo C#
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Report-Integration-Key", "dev-report-integration-key");
var body = new
{
externalUserId = "ext-usr-001",
clientSystemId = "client-system-demo",
returnUrl = "/"
};
var response = await client.PostAsJsonAsync("https://localhost:7019/api/integration/bootstrap-report-session", body);
var payload = await response.Content.ReadFromJsonAsync<BootstrapResponse>();
if (payload?.Success == true && !string.IsNullOrWhiteSpace(payload.LaunchUrl))
{
// Abra payload.LaunchUrl no navegador no fluxo da aplicação hospedeira.
}
public sealed record BootstrapResponse(bool Success, string? Message, string? LaunchUrl, DateTimeOffset? ExpiresAtUtc, string? Reference);
Observabilidade em Runtime
Eventos de segurança e auditoria são registrados para:
- Bootstrap negado e motivo.
- Bootstrap bem-sucedido e contexto da URL gerada.
- Negação/abertura de sessão na rota de integração.
Chamada Externa para Abrir o Servidor de Relatórios (Lado Cliente)
Objetivo
Permitir que um sistema externo abra o AdhocReport.ServerApp completo para um usuário já mapeado no AdhocReport.
Não confundir: ExternalAuth x ReportIntegration
Neste fluxo app-app, a autenticação entre sistemas usa a seção ReportIntegration.
- ReportIntegration (este documento): valida a chamada server-to-server via API key e gera token/launchUrl.
- ExternalAuth: valida credenciais do usuário (username/senha) no login direto pela tela do ReportServer.
Importante:
- No bootstrap (/api/integration/bootstrap-report-session), o sistema não valida senha do usuário via ExternalAuth.
- A validação no bootstrap é de chave compartilhada (RequestApiKey) e integridade/expiração do token.
Como funciona (resumo rápido)
- Seu sistema chama o endpoint de bootstrap no ServerApp.
- O ServerApp valida a chave compartilhada e gera um token temporário (uso único).
- O ServerApp retorna uma launchUrl.
- O navegador abre essa launchUrl.
- O ServerApp autentica o usuário e redireciona para a aplicação completa.
Endpoint
- Método: POST
- Rota: /api/integration/bootstrap-report-session
- Header obrigatório: X-Report-Integration-Key (ou nome configurado no servidor)
Configuração necessária no ReportServer (appsettings)
"ReportIntegration": {
"Enabled": true,
"RequestApiKeyHeaderName": "X-Report-Integration-Key",
"RequestApiKey": "dev-report-integration-key",
"BootstrapTokenLifetimeSeconds": 120,
"BootstrapTokenSigningKey": "dev-bootstrap-signing-key-change-in-production",
"IntegrationReportsRoute": "/integration/entry",
"Cors": {
"AllowedOrigins": [
"https://localhost:7227",
"http://localhost:5148"
]
}
}
O que cada chave faz
- Enabled: liga/desliga o bootstrap app-app.
- RequestApiKeyHeaderName: nome do header esperado na chamada server-to-server.
- RequestApiKey: valor da chave compartilhada entre sistemas.
- BootstrapTokenLifetimeSeconds: validade do token temporário de abertura.
- BootstrapTokenSigningKey: chave usada para assinar e validar o token.
- IntegrationReportsRoute: rota de entrada que consome o token (/integration/entry).
- Cors.AllowedOrigins: origens permitidas para chamadas cross-origin ao endpoint de bootstrap.
Observação importante sobre BootstrapTokenSigningKey
- Essa chave não é hardcoded no fluxo de bootstrap.
- Ela vem da configuração (ReportIntegration:BootstrapTokenSigningKey).
- Se estiver ausente, o bootstrap retorna report-integration-misconfigured.
Body mínimo
{
"externalUserId": "ext-usr-001",
"clientSystemId": "client-system-demo",
"returnUrl": "/"
}
Regras dos campos
- externalUserId: obrigatório; deve existir no AdhocReport.
- clientSystemId: obrigatório; identifica o sistema chamador.
- returnUrl: opcional; deve ser rota relativa iniciando com /.
Exemplo de chamada (cURL)
curl -X POST "https://localhost:7019/api/integration/bootstrap-report-session" \
-H "Content-Type: application/json" \
-H "X-Report-Integration-Key: dev-report-integration-key" \
-d '{"externalUserId":"ext-usr-001","clientSystemId":"client-system-demo","returnUrl":"/"}'
Exemplo de resposta de sucesso
{
"success": true,
"message": "ok",
"launchUrl": "https://localhost:7019/integration/entry?token=...",
"expiresAtUtc": "2026-06-02T18:30:00Z",
"reference": "abc-123"
}
Depois disso, abra launchUrl no navegador (nova aba ou mesma aba, conforme sua UX).
Erros comuns
- invalid-integration-key: chave compartilhada inválida.
- external-user-not-found: usuário externo não mapeado no AdhocReport.
- invalid-return-url: returnUrl inválida (não relativa).
- report-integration-disabled: integração desabilitada no servidor.
Checklist rápido
- Integração habilitada no ServerApp (ReportIntegration:Enabled=true).
- Chave e nome do header alinhados entre cliente e servidor.
- Usuário externo já vinculado (ExternalUserId).
- URL HTTPS acessível entre os ambientes.
- BootstrapTokenSigningKey configurada e protegida por segredo de ambiente.
Observação importante
O app ReportIntegration.BlazorTestClient é uma ferramenta de diagnóstico. Para o cliente final, a integração mínima é: chamar bootstrap + abrir launchUrl.