Suporte assíncrono do Servlet 3 com Spring MVC e Spring Security

Suporte assíncrono do Servlet 3 com Spring MVC e Spring Security

1. Introdução

Neste tutorial rápido, vamos nos concentrar emthe Servlet 3 support for async requests, and how Spring MVC and Spring Security handle these.

A motivação mais básica para a assincronicidade em aplicativos da Web é lidar com solicitações de execução longa. Na maioria dos casos de uso, precisaremos garantir que o principal Spring Security seja propagado para esses threads.

E, é claro, Spring Securityintegrates with @Async fora do escopo do MVC e de processamento de solicitações HTTP também.

2. Dependências do Maven

Para usar a integração assíncrona no Spring MVC, precisamos incluir as seguintes dependências em nossopom.xml:


    org.springframework.security
    spring-security-web
    4.2.1.RELEASE


    org.springframework.security
    spring-security-config
    4.2.1.RELEASE

A versão mais recente das dependências do Spring Security pode ser encontradahere.

3. Spring MVC e@Async

De acordo com odocs oficial, Spring Security integra-se comWebAsyncManager.

A primeira etapa é garantir que nossospringSecurityFilterChain esteja configurado para processar solicitações assíncronas. Podemos fazer isso na configuração Java, adicionando a seguinte linha à nossa classe de configuraçãoServlet:

dispatcher.setAsyncSupported(true);

ou na configuração XML:


    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy
    true


    springSecurityFilterChain
    /*
    REQUEST
    ASYNC

Também precisamos habilitar o parâmetroasync-supported em nossa configuração de servlet:


    ...
    true
    ...

Agora estamos prontos para enviar solicitações assíncronas comSecurityContext propagado com elas.

Mecanismos internos dentro do Spring Security garantirão que nossoSecurityContext não seja mais apagado quando uma resposta for confirmada em outroThread, resultando em um logout do usuário.

4. Casos de Uso

Vamos ver isso em ação com um exemplo simples:

@Override
public Callable checkIfPrincipalPropagated() {
    Object before
      = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    log.info("Before new thread: " + before);

    return new Callable() {
        public Boolean call() throws Exception {
            Object after
              = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            log.info("New thread: " + after);
            return before == after;
        }
    };
}

Queremos verificar se SpringSecurityContext é propagado para o novo encadeamento.

O método apresentado acima terá automaticamente seuCallable executado com oSecurityContext incluído, conforme visto nos logs:

web - 2017-01-02 10:42:19,011 [http-nio-8081-exec-3] INFO
  o.example.web.service.AsyncService - Before new thread:
  [email protected]:
  Username: temporary; Password: [PROTECTED]; Enabled: true;
  AccountNonExpired: true; credentialsNonExpired: true;
  AccountNonLocked: true; Granted Authorities: ROLE_ADMIN

web - 2017-01-02 10:42:19,020 [MvcAsync1] INFO
  o.example.web.service.AsyncService - New thread:
  [email protected]:
  Username: temporary; Password: [PROTECTED]; Enabled: true;
  AccountNonExpired: true; credentialsNonExpired: true;
  AccountNonLocked: true; Granted Authorities: ROLE_ADMIN

Sem configurar oSecurityContext a ser propagado, a segunda solicitação terminará com o valornull.

Existem também outros casos de uso importantes para usar solicitações assíncronas comSecurityContext propagados:

  • queremos fazer várias solicitações externas que podem ser executadas em paralelo e que podem levar um tempo significativo para serem executadas

  • temos algum processamento significativo para fazer localmente e nossa solicitação externa pode ser executada paralelamente a essa

  • outros representam cenários de ignorar, como por exemplo enviar um email

Observe que, se nossas várias chamadas de método foram encadeadas anteriormente de maneira síncrona, a conversão para uma abordagem assíncrona pode exigir resultados de sincronização.

5. Conclusão

Neste breve tutorial, ilustramos o suporte Spring para processamento de solicitações assíncronas em um contexto autenticado.

Do ponto de vista do modelo de programação, os novos recursos parecem enganosamente simples. Mas há certamente alguns aspectos que exigem uma compreensão mais profunda.

Este exemplo também está disponível como um projeto Mavenover on Github.