Show / Hide Table of Contents
Editar no GitHub

Sessões de assinatura - Rest PKI Core

Sessões de assinatura são uma funcionalidade do Rest PKI Core que permitem que seus usuários assinem documentos digitalmente sem que você precise implementar uma página de assinatura digital na sua aplicação.

Para criar uma sessão de assinatura, sua aplicação especifica um returnUrl e recebe de volta um redirectUrl. Sua aplicação então redireciona o usuário para o redirectUrl, local onde ele irá realizar as assinaturas digitais:

Signature session start

Uma vez que o processo seja finalizado, o usuário será redirecionado de volta à sua aplicação no endereço returnUrl especificado durante a criação da sessão. Um query parameter será adicionado à URL contendo o ID da sessão de assinatura (?signatureSessionId=...). Usando esse ID, a sua aplicação chama o Rest PKI Core para obter os documentos assinados pelo usuário:

Signature session end

Criando a sessão de assinatura

Tip

Desse ponto em diante estaremos descrevendo chamadas ao Rest PKI Core. Para conseguir acompanhar, certifique-se de que já fez os Primeiros passos.

Em .NET, chame IRestPkiService.CreateSignatureSessionAsync() e use o RedirectUrl retornado para redirecionar o usuário:

var response = await restPkiService.CreateSignatureSessionAsync(new CreateSignatureSessionRequest() {
    ReturnUrl = "http://localhost:8080/SessionCallback",
});
return Redirect(response.RedirectUrl);

Veja exemplo de criação de sessão de assinatura em .NET.

Em PHP, chame RestPkiServiceInterface.createSignatureSession() e use o campo $redirectUrl retornado para redirecionar o usuário:

$request = new CreateSignatureSessionRequest();
$request->returnUrl = "http://localhost:8080/SessionCallback";

$response = $service->createSignatureSession($request);

header("Location: {$response->redirectUrl}");

Veja exemplo de criação de sessão de assinatura em PHP.

Em Java, chame RestPkiService.CreateSignatureSession() e use o RedirectUrl retornado para redirecionar o usuário:

CreateSignatureSessionRequest request = new CreateSignatureSessionRequest();
request.setReturnUrl("http://localhost:60695/signature-session-rest-core/complete");

CreateSignatureSessionResponse response = restPkiService.CreateSignatureSession(request);

return "redirect:" + response.getRedirectUrl();

Veja exemplo de criação de sessão de assinatura em Java.

Caso esteja chamando a API diretamente:

POST {endpoint}/api/signature-sessions
{
    "returnUrl": "http://localhost:8080/SessionCallback"
}

Vamos analisar o returnUrl utilizado nos exemplos acima:

http://localhost:8080/SessionCallback
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
Endereço da sua app   Rota para o tratamento de retorno

Ao adaptar os exemplos para a sua aplicação, você precisa alterar a primeira porção para o endereço da sua própria aplicação e também a rota para o tratamento do retorno na sua aplicação (veja a seção abaixo).

Implementando o tratamento de retorno

O returnUrl é o endereço para no qual o Rest PKI Core enviará o seu usuário de volta para a sua aplicação uma vez que o processo de assinatura seja concluído.

Note

Até aqui, estamos usando /SessionCallback como URL relativa do tratamento de retorno, porém sinta-se à vontade para usar a URL relativa mais adequada à sua aplicação

Em .NET, a implementação do tratamento de retorno seria algo como:

public class SessionCallbackController : Controller {
    ... 
    public async Task<IActionResult> Index(Guid signatureSessionId) {
        var session = await restPkiService.GetSignatureSessionAsync(signatureSessionId.Value);
        if (session.Status != SessionStatus.Completed) {
            return Redirect("/");
        }
        return View(session);
    }
}

Veja exemplo de tratamento de retorno em .NET.

Em PHP, a implementação do tratamento de retorno seria algo como:

$sessionId = $_GET['signatureSessionId'];

$session = $session->getSignatureSession($sessionId);
if ($session->status != SignatureSessionStatus::COMPLETED) {
    header("Location: http://localhost:8000/");
}

Veja exemplo de tratamento de retorno em PHP.

Em Java, a implementação do tratamento de retorno seria algo como:

@Controller
public class SessionCallbackController {
    ...
    public String index(
        Model model, 
        @RequestParam(value="signatureSessionId") String sessionId
    ) throws RestException {
        SignatureSession session = restPkiService.getSignatureSession(UUID.fromString(sessionId));
        if (session.getStatus() != SignatureSessionStatus.Completed){
            return "redirect:/";
        }
        model.addAttribute("session", session);
        return "signature-callback/index";
    }
}

Veja exemplo de tratamento de retorno em Java.

Note que verificamos o estado (Status) da sessão e enviamos o usuário para um local padrão caso o estado não seja Completed.

Note

Quando um usuário é redirecionado de volta à sua aplicação, a sessão terá um de dois possíveis estados: Completed ou UserCancelled, esse último ocorrendo quando a sessão é cancelada pelo usuário. Seu código deve sempre checar esse estado, pois é perfeitamente normal um usuário ser direcionado ao endereço de tratamento de retorno porque cancelou a sessão.

Em .NET, a view de Razor seria algo como:

@using Lacuna.RestPki.Api
@using Lacuna.RestPki.Client
@model SignatureSession
<h2>Signed documents</h2>
<ul>
    @foreach (var document in Model.Documents)
    {
        <li>
            <a href="@document.SignedFile.Location">@document.SignedFile.Name</a>
        </li>
    }
</ul>

Em PHP, o lado do cliente seria algo como:

<h2>Signed documents</h2>
<ul>
    <?php for ($i = 0; $i < count($session->documents); $i++) { 
        $document = $session->documents[$i]; ?>

        <li>
            <a href="<?= $document->signedFile->location ?>"><?= $document->signedFile->name ?></a>
        </li>
    <?php } ?>
</ul>

Em Java, a view de Spring seria algo como:

<h2>Signed documents</h2>
<ul th:each="document : ${session.getDocuments()}">
    <li>
        <a th:href="${document.getSignedFile().getLocation()">
            <span th:text="${document.getSignedFile().getName()}"/>
        </a>
    </li>
</ul>

Pré-definindo os documentos a serem assinados

As sessões que criamos até aqui solicitam que o usuário faça upload dos documentos a serem assinados. Você pode alternativamente especificar os documentos que devem ser assinador no momento da criação da sessão. Nesse caso, o usuário não poderá fazer upload de documentos, podendo apenas assinar os documentos pré-definidos pela sua aplicação.

Em .NET:

string pdfPath = ...;
Stream xmlStream = ...;
var documents = new List<SignatureSessionDocumentToSign> {
    new SignatureSessionDocumentToSign {
        File = FileReference.FromFile(pdfPath),
    },
    new SignatureSessionDocumentToSign {
        File = FileReference.FromStream(xmlStream, "doc.xml"),
    },
    ...
};
var response = await restPkiService.CreateSignatureSessionAsync(new CreateSignatureSessionRequest() {
    ...
}, documents: documents);
return Redirect(response.RedirectUrl);

Em Java:

CreateSignatureSessionRequest request = new CreateSignatureSessionRequest();
String pdfPath = ...;
Stream xmlStream = ...;

List<SignatureSessionDocumentToSign> documents = new ArrayList<>();

SignatureSessionDocumentToSign document = new SignatureSessionDocumentToSign();
document.setFile(FileReference.fromFile(pdfPath, null, "application/pdf"));
documents.add(document);

document = new SignatureSessionDocumentToSign();
document.setFile(FileReference.FromStream(pdfPath, "doc.xml", null));
documents.add(document);

CreateSignatureSessionResponse response = restPkiService.createSignatureSession(request, null, null, documents);

return "redirect:" + response.getRedirectUrl();

Integração direta por API:

POST {endpoint}/api/signature-sessions
{
    ...
    "documents": [
        {
            "file": {
                "content": "Base64EncodedBytes==",
                "name": "doc1.pdf"
            }
        },
        {
            "file": {
                "url": "https://yourapp.com/doc2.pdf"
            }
        },
        ...
    ]
}

Para mais informações veja Referenciando arquivos.

Desabilitando downloads

Caso tenha a impressão de que alguns de seus usuários, ao invés de concluirem a sessão e retornarem à sua aplicação, simplesmente fazem o download dos arquivos assinados e fecham a aba do navegador, de modo que a sua aplicação não chega a tomar conhecimento dos documentos, você pode desabilitar a função de download dos arquivos assinados durante a sessão de assinatura especificando DisableDownloads = true ao criar a sessão.

Em .NET:

var response = await restPkiService.CreateSignatureSessionAsync(new CreateSignatureSessionRequest() {
    ...
    DisableDownloads = true,
});
return Redirect(response.RedirectUrl);

Em PHP:

$request = new CreateSignatureSessionRequest();
$request->returnUrl = "http://localhost:8080/session-callback";
$request->disableDownloads = true;

$response = $service->createSignatureSession($request);

header("Location: {$response->redirectUrl}");

Em Java:

CreateSignatureSessionRequest request = new CreateSignatureSessionRequest();
request.setReturnUrl("http://localhost:60695/signature-session-rest-core/complete");
request.setDisableDownloads(true);

CreateSignatureSessionResponse response = restPkiService.createSignatureSession(request);

return "redirect:" + response.getRedirectUrl();

Integração direta por API:

POST {endpoint}/api/signature-sessions
{
    ...
    "disableDownloads": true
}

Nesse caso, os usuários só conseguirão baixar os arquivos assinados na sua aplicação e, portanto, ficarão menos inclinados a interromper o processo prematuramente fechando a aba do navegador.

Note

Outra forma de lidar com esse problema é optar pelo Fluxo com webhook (veja seção abaixo)

Fluxo com webhook

No fluxo padrão descrito acima, a sua aplicação toma conhecimento dos documentos assinados quando o usuário é redirecionado de volta com a query parameter signatureSessionId adicionada à URL.

Uma alternativa a esse fluxo é tomar conhecimento dos documentos assinados através de notificação de evento por webhook. Nesse caso, pode-se abrir a página de assinatura em uma nova aba, a qual é fechada ao final do processo, dispensando a implementação do "tratamento de retorno" (é necessário, entretanto, implementar o recebimento de notificação de evento).

Esse fluxo tem a vantagem de não depender do retorno do usuário à sua aplicacão para tratar os documentos que são assinados. Além disso, esse fluxo facilita o uso de processamento em background, recurso que melhora significativamente a experiência do usuário.

Para abrir a página de assinatura em outra aba, é preciso utilizar um anchor (elemento <a>) com target="_blank":

<a href="..." target="_blank">Sign documents</a>
Note

Outra opção é abrir a aba com uma chamada ao window.open() em Javascript

Além disso, é preciso omitir o parâmetro returnUrl ao criar a sessão.

Em .NET:

var response = await restPkiService.CreateSignatureSessionAsync(new CreateSignatureSessionRequest() {
    ReturnUrl = null,
    EnableBackgroundProcessing = true,
});
return Redirect(response.RedirectUrl);

Veja exemplo do início do fluxo com webhook em .NET.

Em PHP:

$request = new CreateSignatureSessionRequest();
$request->returnUrl = null;
$request->enableBackgroundProcessing = true;

$response = $service->createSignatureSession($request);

header("Location: {$response->redirectUrl}");

Veja exemplo do início do fluxo com webhook em PHP.

Em Java:

CreateSignatureSessionRequest request = new CreateSignatureSessionRequest();
request.setEnableBackgroundProcessing(true);

CreateSignatureSessionResponse response = restPkiService.createSignatureSession(request);

return "redirect:" + response.getRedirectUrl();

Veja exemplo do início do fluxo com webhook em Java.

Integração direta por API:

POST {endpoint}/api/signature-sessions
{
    "returnUrl": null,
    "enableBackgroundProcessing": true
}

Dessa forma, a aba será fechada pelo Rest PKI Core ao final do processo.

Melhorando a experiência do usuário

Você pode optar por alguns dos recursos abaixo para melhorar a experiência do usuário durante suas sessões de assinatura:

  • Requisitos de certificados podem ser usados para restringir os certificados que o usuário poderá escolher
  • Validação de arquivos
  • Processamento em background
  • Metadados de documentos
Back to top Copyright © 2015-2020 Lacuna Software