Skip to content

12. Aplicativo web MVC [personne] – versão 7

12.1. Introduction

Nesta versão, partimos do princípio de que pode haver navegadores dos usuários que tenham desativado:

  1. o reenvio dos cookies enviados pelo servidor
  2. a execução de código JavaScript incorporado nas páginas HTML exibidas

No entanto, queremos que esse tipo de navegador possa utilizar nosso aplicativo. O ponto 2 nos remete à versão 2 do nosso aplicativo, já que o JavaScript passou a ser utilizado a partir da versão 3. A versão 2 fazia o aplicativo funcionar sem JavaScript; portanto, o ponto 2 está resolvido.

O ponto 1 pode ou não ser complicado de lidar. A versão 6 do nosso aplicativo funcionava sem cookies. Ao mesclar as versões 2 e 6, obtemos o resultado solicitado. Vamos adicionar uma restrição adicional: o aplicativo deve gerenciar uma sessão. Essa restrição não é sem sentido. Em um aplicativo em que os usuários precisam se autenticar, o servidor deve memorizar o par (identificador/senha) do usuário para evitar que ele precise se autenticar a cada página que solicitar.

Até agora, utilizamos três soluções para armazenar informações ao longo das trocas entre cliente e servidor:

  1. a sessão
  2. os cookies
  3. os campos ocultos.

A solução 2 pode ser descartada, pois o navegador do cliente pode ter desativado o uso de cookies.

A solução 3 é a da versão 6 analisada anteriormente. Ela não pode ser utilizada por motivos de segurança. Se o par (login/senha) estiver encapsulado em cada página enviada ao navegador, isso significa que ele transita pela rede a cada troca cliente/servidor. Isso não é bom para a segurança do aplicativo. Pode-se, então, considerar o uso do protocolo HTTPS, que criptografa as trocas cliente/servidor. No entanto, utilizá-lo para cada página do aplicativo aumentará a carga do servidor.

Pode-se querer descartar a solução 1 porque ela também se baseia em cookies. Na primeira troca cliente/servidor, o servidor envia ao cliente um token de sessão, que este reenviará ao servidor a cada nova solicitação. Graças a esse token, o servidor poderá reconhecer seu cliente e atribuir-lhe informações que havia memorizado durante uma troca anterior. O token de sessão é enviado pelo servidor em um cookie. O navegador que não desativou os cookies pode reenviar esse cookie nas solicitações seguintes. Se tiver desativado os cookies, ele dispõe de outra solução: pode incluir o token de sessão na URL que está solicitando. É isso que vemos agora, retomando a análise do arquivo [index.jsp] da versão 4:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<c:redirect url="/main"/>

Vale lembrar que a linha 5 acima redireciona o cliente para a URL [/personne4/main?jsessionid=XX], onde XX é o token de sessão, conforme mostra a captura de tela abaixo, obtida após a solicitação da URL [http://localhost:8080/personne4]:

Image

Vamos examinar mais de perto o funcionamento da tag <c:redirect> no que diz respeito ao token de sessão. Consideremos um navegador em que os cookies são aceitos. A seguir, configuramos o navegador Firefox:

Image

Em [1], habilitamos os cookies e, em [2], excluímos os que já existem para partir de uma situação conhecida. Em seguida, solicitamos a URL [http://localhost:8080/personne4]. Obtemos a seguinte resposta:

Image

A solicitação inicial do cliente, HTTP, foi a seguinte:

1
2
3
4
5
6
7
8
9
GET /personne4/ HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Vale ressaltar que o cliente não envia nenhum cookie de sessão. A resposta HTTP enviada pelo servidor é a seguinte:

1
2
3
4
5
6
7
HTTP/1.x 302 Déplacé Temporairement
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=1ACA010A6BA28FB9E30A1D3184F574BC; Path=/personne4
Location: http://localhost:8080/pessoa4/main;jsessionid=1ACA010A6BA28FB9E30A1D3184F574BC
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Tue, 23 May 2006 09:10:05 GMT
  • linha 1: o servidor solicita que o cliente se redirecione
  • linha 3: o servidor envia um token de sessão associado ao atributo [JSESSIONID]
  • linha 4: a URL de redirecionamento contém o token de sessão. A tag <c:redirect> o inseriu ali porque o cliente não havia enviado nenhum cookie de sessão.

O navegador, ao qual foi solicitada a redireção, fez então a seguinte solicitação:

GET /personne4/main;jsessionid=1ACA010A6BA28FB9E30A1D3184F574BC HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: JSESSIONID=1ACA010A6BA28FB9E30A1D3184F574BC
  • linha 1: ele solicita a URL de redirecionamento, incluindo o token de sessão. É por isso que, na captura de tela, o navegador exibe essa URL.
  • linha 10: o navegador reenvia o token de sessão que o servidor lhe enviou na troca anterior. Esse é o funcionamento normal dos cookies quando eles estão habilitados no navegador do cliente. Caso contrário, os cookies recebidos não são reenviados.

O servidor respondeu o seguinte a essa segunda solicitação:

1
2
3
4
5
HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 2376
Date: Tue, 23 May 2006 09:10:05 GMT

Ele encontrou a página solicitada e a envia. Observe que ele não envia mais o token de sessão. Esse é o funcionamento normal do token de sessão: ele é enviado ao navegador uma única vez pelo servidor na forma de um cookie, e o navegador o reenvia a cada solicitação para ser reconhecido.

Agora, com o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4] digitando-a manualmente. Obtemos então a seguinte página:

Image

Percebemos que a URL exibida pelo navegador não contém mais o token de sessão. Vejamos a primeira troca entre cliente e servidor:

O navegador fez a seguinte solicitação:

GET /personne4 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: JSESSIONID=1ACA010A6BA28FB9E30A1D3184F574BC

É exatamente a mesma solicitação da vez anterior, com uma diferença, porém: na linha 10, o navegador reenvia o token de sessão que havia recebido na primeira troca. Mais uma vez, esse é o funcionamento normal se os cookies do navegador estiverem ativos.

O servidor enviou a seguinte resposta:

1
2
3
4
5
HTTP/1.x 302 Déplacé Temporairement
Server: Apache-Coyote/1.1
Location: http://localhost:8080/pessoa4/
Transfer-Encoding: chunked
Date: Tue, 23 May 2006 09:24:39 GMT

Ele solicita que o cliente seja redirecionado. Como recebeu um token de sessão do cliente, ele dá continuidade à sessão e não envia um novo token de sessão. Pelo mesmo motivo, a tag <c:redirect> não inclui esse token de sessão na URL de redirecionamento. É por isso que a URL exibida na captura de tela acima não contém nenhum token de sessão.

Diante disso, devemos reter a seguinte regra: a tag <c:redirect> só inclui o token de sessão na URL de redirecionamento se o cliente não tiver enviado o cabeçalho HTTP:

Cookie: JSESSIONID=1ACA010A6BA28FB9E30A1D3184F574BC

Essa regra também se aplica à tag <c:url>, que veremos mais adiante.

O que acontece com um navegador no qual os cookies foram desativados? Vamos testar. Primeiro, reinicializamos o navegador:

Image

Em [1], desativamos os cookies e, em [2], excluímos os que já existem para partirmos de uma situação conhecida. Em seguida, acessamos a URL [http://localhost:8080/personne4]. Obtemos a seguinte resposta:

Image

Obtemos o mesmo resultado que anteriormente. No entanto, as trocas de dados em HTTP não são exatamente as mesmas:

GET /personne4/ HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

HTTP/1.x 302 Déplacé Temporairement
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=911B8156E0A9D32C2D256020C898E05C; Path=/personne4
Location: http://localhost:8080/pessoa4/main;jsessionid=911B8156E0A9D32C2D256020C898E05C
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Tue, 23 May 2006 09:39:55 GMT

GET /personne4/main;jsessionid=911B8156E0A9D32C2D256020C898E05C HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 2376
Date: Tue, 23 May 2006 09:39:55 GMT
  • linhas 1-9: a solicitação nº 1 do navegador. Ele não envia nenhum cookie de sessão.
  • linhas 11-17: a resposta do servidor, que solicita que ele seja redirecionado para outra URL. Ele envia um cookie de sessão na linha 13: a tag <c:redirect> incluiu o token na URL de redirecionamento da linha 14.
  • linhas 19-27: a solicitação nº 2 do navegador. Ele não retorna o cookie de sessão que o servidor acabou de enviar porque seus cookies estão desativados.
  • linhas 29-33: a resposta do servidor. Percebe-se que, embora o navegador não tenha enviado um cookie de sessão, o servidor não inicia uma nova sessão, como seria de se esperar. Isso fica evidente pelo fato de ele não enviar o cabeçalho HTTP [Set-Cookie], como havia feito na linha 13. Isso significa que ele dá continuidade à sessão anterior. Ele conseguiu recuperá-la graças ao token de sessão presente na URL solicitada pelo navegador na linha 19.

Vale ressaltar que o servidor acompanha uma sessão recuperando o token de sessão enviado pelo cliente de duas maneiras possíveis:

  • no cabeçalho HTTP [Set-Cookie] enviado pelo cliente
  • na URL solicitada pelo cliente

Agora, com o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4] digitando-a manualmente, como foi feito quando os cookies estavam habilitados. Obtemos então a seguinte página:

Image

Temos um resultado diferente daquele obtido quando os cookies estavam permitidos: o token de sessão está na URL exibida pelo navegador. Vamos explicar esse resultado sem analisar as trocas de dados HTTP que ocorreram:

[cookies autorisés]

  • na segunda solicitação da URL [http://localhost:8080/personne4], o navegador do cliente havia reenviado o cookie de sessão que havia recebido do servidor na primeira solicitação dessa mesma URL. A tag <c:redirect> não havia, portanto, incluído o token de sessão no endereço de redirecionamento.

[cookies inhibés]

  • na segunda solicitação da URL [http://localhost:8080/personne4], o navegador do cliente não envia o cookie de sessão que recebeu do servidor na primeira solicitação dessa mesma URL, uma vez que seus cookies estão desativados. A tag <c:redirect> inclui, portanto, o token de sessão no endereço de redirecionamento. É por isso que ele aparece na captura de tela acima.

As tags <c:redirect> e <c:url> permitem incluir o token de sessão nas URLs. Essa é a solução proposta aqui.

12.2. O projeto Eclipse

Para criar o projeto Eclipse [mvc-personne-07] do aplicativo web [/personne7], duplicaremos o projeto [mvc-personne-06] seguindo o procedimento descrito no parágrafo 6.2.

12.3. Configuração da aplicação web [personne7]

O arquivo web.xml da aplicação /personne7 é o seguinte:


<?xml version="1.0" encoding="UTF-8"?>
...
    <display-name>mvc-personne-07</display-name>
...

Esse arquivo é idêntico ao da versão anterior, exceto pela linha 3, onde o nome de exibição da aplicação web foi alterado para [mvc-personne-07]. A página inicial [index.jsp] permanece inalterada.


...
<c:redirect url="/do/formulaire"/>

12.4. O código das visualizações

As visualizações [formulaire, réponse, erreurs] voltam a ser o que eram na versão 2, c.a.d, sem JavaScript. No entanto, elas mantêm as tags JSTL das versões anteriores.

12.4.1. A visualização [formulaire]

Image

Foram removidos os botões associados ao código JavaScript.

[formulaire.jsp]:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<html>
  <head>
    <title>Personne - formulaire</title>
  </head>
  <body>
    <center>
      <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" action="<c:url value="validationFormulaire"/>" method="post">
        <table>
          <tr>
            <td>Nom</td>
            <td><input name="txtNom" value="${nom}" type="text" size="20"></td>
          </tr>
          <tr>
            <td>Age</td>
            <td><input name="txtAge" value="${age}" type="text" size="3"></td>
          </tr>
          <tr>
        </table>
        <table>
          <tr>
            <td><input type="submit" name="bouton" value="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="submit" name="bouton" value="Effacer"></td>
          </tr>
        </table>
      </form>
    </center>
  </body>
</html>
  • linha 14: a URL de destino do POST é definida com a tag <c:url> para que o token de sessão esteja presente, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
  • O formulário possui dois botões do tipo [submit]: [Envoyer] (linha 28) e [Effacer] (linha 30). Ambos os botões têm o mesmo nome: bouton. Ao clicar no POST, o navegador enviará o parâmetro:
  • botão=Enviar se a solicitação POST tiver sido acionada pelo botão [Enviar]
  • botão=Apagar se a solicitação POST tiver sido acionada pelo botão [Apagar]

É esse parâmetro que nos ajudará a definir a ação exata a ser realizada, já que a URL [/do/validationFormulaire] agora corresponde a duas ações distintas.

12.4.2. A visualização [réponse]

Image

[réponse.jsp]:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Personne - réponse</h2>
    <hr>
    <table>
        <tr>
          <td>Nom</td>
        <td>${nom}</td>
      </tr>
        <tr>
          <td>Age</td>
        <td>${age}</td>
      </tr>
    </table>      
    <br>
    <a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
  </body>
</html>

  • linha 24: a URL de destino do HREF é escrita com a tag <c:url> para que o token de sessão esteja presente, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].

12.4.3. A visualização [erreurs]

Image

[erreurs.jsp]:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
            <c:forEach var="erreur" items="${erreurs}">
                <li>${erreur}</li>
            </c:forEach>
    </ul>
    <br>
    <a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
  </body>
</html>

  • linha 18: a URL de destino do HREF é escrita com a tag <c:url> para que o token de sessão esteja presente, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].

Recomenda-se ao leitor que teste essas novas visualizações seguindo o princípio apresentado nas versões anteriores.

12.5. O controlador [ServletPersonne]

O controlador [ServletPersonne] do aplicativo web [/personne7] é o seguinte:

package istia.st.servlets.personne;

...

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parâmetros de instância
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse","lienRetourFormulaire"};
    private Map params=new HashMap<String,String>();

     // inicialização
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
    }

     // GET
    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

...
         // recupera-se o método de envio da solicitação
        String méthode=request.getMethod().toLowerCase();
         // recupera-se a ação a ser executada
        String action=request.getPathInfo();
...
        if(méthode.equals("post") && action.equals("/validationFormulaire")){
             // validação do formulário de preenchimento
            doValidationFormulaire(request,response);
            return;
        }
        if(méthode.equals("get") && action.equals("/retourFormulaire")){
             // retorno ao formulário de preenchimento
            doRetourFormulaire(request,response);
            return;
        }
         // outros casos
        doInit(request,response);
    }

     // exibição do formulário vazio
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
...
    }

     // exibição do formulário pré-preenchido
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // exibição do formulário
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

     // exibição do formulário vazio
    void doEffacer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // prepara-se o modelo do formulário
        HttpSession session = request.getSession(true);        
        session.setAttribute("nom", "");
        session.setAttribute("age", "");
         // exibição do formulário
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

     // validação do formulário
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
         // recupera-se o botão que acionou o POST
        String bouton = request.getParameter("bouton").toLowerCase();
         // processamento de acordo com o botão que acionou o POST
        if(bouton==null){
            doInit(request,response);
            return;
        }
        if("envoyer".equals(bouton)){
            doEnvoyer(request,response);
            return;
        }
        if("effacer".equals(bouton)){
            doEffacer(request,response);
            return;
        }
    }

     // validação do formulário
    void doEnvoyer(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
         // recuperam-se os parâmetros
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
         // que são armazenados na sessão
        HttpSession session = request.getSession(true);        
        session.setAttribute("nom", nom);
        session.setAttribute("age", age);
         // o link de retorno ao formulário é inserido no modelo das visualizações [réponse, erreurs]
        request.setAttribute("lienRetourFormulaire", (String)params.get("lienRetourFormulaire"));    
         // verificação dos parâmetros
        ArrayList<String> erreursAppel = new ArrayList<String>();
    ...
         // há erros nos parâmetros?
        if (erreursAppel.size() != 0) {
             // enviando a página de erros
            request.setAttribute("erreurs", erreursAppel);
            getServletContext().getRequestDispatcher(urlErreurs).forward(
                    request, response);
            return;
        }
         // os parâmetros estão corretos — enviamos a página de resposta
        getServletContext().getRequestDispatcher((String)params.get("urlReponse")).forward(request,
                response);
        return;
    }

     // post
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
...
    }
}
  • linha 35: a ação [/retourFormulaire] é executada por um GET e não mais por um POST, como na versão anterior.
  • linhas 70-87: a ação [/validationFormulaire] é executada por um POST, acionado por um clique emum dos botões [Envoyer] ou [Effacer] da visualização [formulaire]. O método [doValidationFormulaire] trata esses dois casos por meio de dois métodos diferentes.
  • linhas 90-103: o método [doEnvoyer] corresponde ao método [doValidationFormulaire] da versão anterior. Os dados inseridos são colocados na sessão (linhas 96-98), enquanto na versão anterior eram colocados na consulta.
  • linhas 58-67: o novo método [doEffacer] deve exibir um formulário vazio. Seria possível utilizar o método [doInit], que já realiza essa tarefa. Aqui, aproveitamos para também apagar os elementos [nom, age] da sessão, para que ela continue refletindo o estado mais recente do formulário.
  • linhas 50-55: solicitam a exibição da visualização [formulaire] sem inicialização aparente do modelo dessa visualização. Esse modelo é, na verdade, constituído pelos elementos [nom, age] que já estão na sessão. Não há necessidade de fazer mais nada.

12.6. Tests

Inicie ou reinicie o Tomcat após ter integrado o projeto Eclipse [personne-mvc-07] e, em seguida, acesse a URL [http://localhost:8080/personne7] com um navegador no qual os cookies foram desativados e os já existentes foram excluídos. Obtém-se a seguinte resposta:

Image

O código-fonte recebido pelo navegador é o seguinte:

1
2
3
<form name="frmPersonne" action="validationFormulaire;jsessionid=9D4CC83FEFB51AE78B1FD71EC66F9EF3" method="post">
...
</form>

Na linha 1, o token de sessão está na URL de destino do POST.

Vamos preencher o formulário e enviá-lo:

Image

O código-fonte recebido pelo navegador é o seguinte:

1
2
3
4
...
    <br>
    <a href="retourFormulaire;jsessionid=9D4CC83FEFB51AE78B1FD71EC66F9EF3">Retour au formulaire</a>
  </body>

Linha 3: o token de sessão está na URL de destino do link.