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.