Sessões e Segurança
Sessões de documento e controle de acesso
Um token Doconut identifica um documento aberto. Se qualquer requisição que o contenha fosse atendida, quem o obtiver poderia ler todas as páginas. Esta página explica o que uma sessão de documento contém, quanto tempo ela dura e como DocImage.axd decide quem pode ver suas páginas — em um único servidor e em uma fazenda de servidores.
O que uma sessão de documento contém
Cada OpenDocumentAsync bem‑sucedido cria uma sessão, mantida na memória:
- o visualizador de formato carregado — a instância do motor que mantém o documento analisado,
- estado por página — rotação, inversões e os dados de anotação que o usuário aplica no widget,
- o índice de busca opcional, construído na primeira pesquisa (ou carregado de um arquivo
.srhpré‑construído), - a marca d'água da sessão proveniente de
DocOptions.Watermark.
Tempo de vida
As sessões expiram em uma janela deslizante: DocOptions.TimeOut minutos (padrão 60), reiniciada a cada requisição que apresenta o token. Quando uma sessão termina — por expiração ou por CloseDocument(token) — seu motor de documento é liberado e sua memória é liberada imediatamente.
// A short-lived session for a one-shot preview
var token = await viewer.OpenDocumentAsync(path, new DocOptions { TimeOut = 10 });Uma requisição com um token expirado recebe uma imagem de erro contendo Document session not found. Please re-open document. A página deve abrir o documento novamente para obter um novo token. Em um único servidor, reciclar o pool de aplicação também encerra todas as sessões.
Páginas são servidas apenas para a sessão que as abriu
Com UnsafeMode = false — o padrão — abrir um documento concede acesso à sessão ASP.NET da requisição que o abriu, gravando uma entrada secure-{token} nessa sessão. DocImage.axd requer o próprio estado de sessão e serve uma página somente quando a sessão solicitante contém essa entrada. Qualquer outro navegador que apresente o mesmo token recebe uma imagem de erro contendo You Are Not Authorized To View This Page.
Doconut.DoconutHost.Initialize(options =>
{
// false (the default): DocImage.axd serves a page only to the ASP.NET session that opened
// the document. The handler asks for session state itself; it only needs the site not to
// turn session state off in Web.config.
options.UnsafeMode = false;
});Três consequências práticas:
- O ponto de abertura precisa de estado de sessão. Controladores MVC e páginas Web Forms o possuem por padrão. Um
IHttpHandlerpersonalizado não o tem, a menos que implementeSystem.Web.SessionState.IRequiresSessionState. Uma abertura que roda sem sessão não tem nada a conceder, portanto o visualizador exibe "You Are Not Authorized To View This Page." em todas as páginas. - O estado de sessão deve permanecer ativo.
<sessionState mode="Off" />emWeb.configdesativa tanto a concessão quanto a verificação, e todas as páginas são recusadas. - O navegador deve enviar o cookie de sessão. As requisições do widget são same-origin, portanto carregam
ASP.NET_SessionIdautomaticamente. Um cliente sem jar de cookies — um script, uma chamada servidor‑para‑servidor, uma configuração cross‑origin que remove cookies — é recusado. Essa é a funcionalidade em ação.
UnsafeMode = true desliga a verificação: qualquer requisição que contenha o token é atendida. É um interruptor global para todos os documentos, sem sobrescrita por documento. Mantenha‑lo false.
Revogação
CloseDocument(token) faz mais do que liberar memória: ele remove a entrada secure-{token} da sessão da requisição atual e revoga o token, de modo que um token fechado é recusado imediatamente.
Fazendas de servidores: tickets assinados
Em uma fazenda, a próxima requisição pode chegar a um servidor que nunca viu o documento, em um processo de trabalho diferente, com sua própria sessão ASP.NET. A concessão de sessão não pode segui‑la. O modo distribuído a substitui por um ticket assinado vinculado ao navegador: cada nó compartilha um único armazenamento para sessões de documento e uma chave de assinatura, e DocImage.axd aceita uma requisição quando seu ticket é válido para aquele token, aquele navegador e — quando o usuário está autenticado — aquele usuário.
A configuração, idêntica em cada nó:
// Global.asax.cs - Application_Start
Doconut.DoconutHost.Initialize(
options => options.UnsafeMode = false, // the ticket check only runs when this is false
services => services.AddDoconutDistributed(d =>
{
d.Store = CloudLocation.FileShare;
d.FileShareRootPath = @"\\fileserver\doconut-shared"; // a folder every node can reach
d.SigningKey = farmKey; // at least 32 bytes, the SAME on every node
}));O ponto de abertura então vincula o ticket ao navegador antes de abrir, e devolve o ticket junto com o token:
- defina
DocOptions.BrowserId = DoconutFarmBinding.EnsureBrowserId(System.Web.HttpContext.Current, securityOptions)— ele gera o cookiedoconut-clientao qual o ticket está vinculado — eDocOptions.UserId = DoconutFarmBinding.ResolveUserId(System.Web.HttpContext.Current); - após
OpenDocumentAsync, retorneviewer.AccessTokenjuntamente com o token; - na página, passe ambos ao widget:
objViewer.View(token, access).
Doconut.MvcSample.WebFarm no pacote de exemplos é um nó de fazenda completo e executável, e o guia de migração ao lado explica cada passo.
Mantenha a chave de assinatura fora do controle de versão: ela tanto assina os tickets quanto criptografa os documentos no armazenamento compartilhado. Um nó com uma chave diferente rejeita todos os tickets emitidos pelos demais.
Teste uma fazenda com um navegador real, ou um script que mantém cookies. Um cliente sem o cookie doconut-client não recebe um 401: ele recebe a imagem de erro "não autorizado" com status 200, cerca de 2 KB, onde uma página real tem dezenas a centenas de kilobytes.
Lista de verificação para produção
- Mantenha
UnsafeMode = false(o padrão). - Abra documentos a partir de requisições que possuam estado de sessão, e nunca desative o estado de sessão.
- Certifique‑se de que o cookie de sessão alcance
DocImage.axd(mesma origem, HTTPS, uma políticaSameSiteque o permita). - Em uma fazenda, use o modo distribuído com uma única chave de assinatura compartilhada por todos os nós.
- Chame
CloseDocumentquando o usuário sair de um documento — memória e segurança se beneficiam. - Nunca registre ou compartilhe tokens; trate‑os como credenciais de curta duração.
Esta página foi útil?