Guia para a Sessão da Primavera
1. Visão geral
Spring Session tem o objetivo simples de liberar o gerenciamento de sessão das limitações da sessão HTTP armazenada no servidor.
A solução facilita o compartilhamento de dados da sessão entre serviços na nuvem sem estar vinculado a um único contêiner (ou seja, Tomcat). Além disso, ele suporta várias sessões no mesmo navegador e o envio de sessões em um cabeçalho.
Neste artigo, usaremosSpring Session para gerenciar informações de autenticação em um aplicativo da web. EnquantoSpring Session pode persistir os dados usando JDBC, Gemfire ou MongoDB, usaremosRedis.
Para obter uma introdução aRedis, verifique o artigothis.
2. Um Projeto Simples
Vamos primeiro criar um projetoSpring Boot simples para usar como base para nossos exemplos de sessão mais tarde:
org.springframework.boot
spring-boot-starter-parent
1.4.0.RELEASE
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
Nosso aplicativo é executado comSpring Boote o pom pai fornece versões para cada entrada. A versão mais recente de cada dependência pode ser encontrada aqui:spring-boot-starter-security,spring-boot-starter-web,spring-boot-starter-test.
Vamos também adicionar algumas propriedades de configuração para nosso servidor Redis emapplication.properties:
spring.redis.host=localhost
spring.redis.port=6379
3. Configuração de inicialização do Spring
Primeiro, vamos demonstrar a configuração deSpring Session com Boot.
Nota: Você não precisa concluir as seções 3 e 4. Apenas escolha um dependendo se você está ou não usandoSpring Boot para configurarSpring Session.
3.1. Dependências
Adicione estas dependências ao nosso projeto:
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.session
spring-session
Estamos usando o pom pai de inicialização para definir as versões aqui, portanto elas garantem que funcionem com nossas outras dependências. A versão mais recente de cada dependência pode ser encontrada aqui:spring-boot-starter-data-redis,spring-session.
3.2. Configuração da Sessão Spring
Agora vamos adicionar uma classe de configuração paraSpring Session:
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
}
4. Configuração padrão do Spring (sem inicialização)
Vamos também dar uma olhada na integração e configuração despring-session sem Spring Boot - apenas com Spring simples.
4.1. Dependências
Primeiro, se estivermos adicionandospring-session a um projeto Spring padrão, precisaremos definir explicitamente:
org.springframework.session
spring-session
1.2.2.RELEASE
org.springframework.data
spring-data-redis
1.5.0.RELEASE
As versões mais recentes desses módulos podem ser encontradas aqui:spring-session,spring-data-redis
4.2. Configuração da Sessão Spring
Agora vamos adicionar uma classe de configuração paraSpring Session:
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
Como você pode ver, as diferenças são mínimas - agora só temos que definir nosso beanJedisConnectionFactory explicitamente - o Boot faz isso por nós.
Em ambos os tipos@EnableRedisHttpSessione a extensão deAbstractHttpSessionApplicationInitializer criará e conectará um filtro na frente de toda a nossa infraestrutura de segurança para procurar sessões ativas e preencher o contexto de segurança a partir dos valores armazenados emRedis .
Agora vamos concluir este aplicativo com um controlador e a configuração de segurança.
5. Configuração da Aplicação
Navegue até o arquivo principal do aplicativo e adicione um controlador:
@RestController
public class SessionController {
@RequestMapping("/")
public String helloAdmin() {
return "hello admin";
}
}
Isso nos dará um ponto final para testar.
Em seguida, adicione nossa classe de configuração de segurança:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("password").roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
Isso protege nossos terminais com autenticação básica e configura um usuário para testar.
6. Test
Finalmente, vamos testar tudo - definiremos um teste simples aqui que nos permitirá fazer 2 coisas:
-
consumir o aplicativo da web ao vivo
-
fale com Redis
Vamos primeiro configurar as coisas:
public class SessionControllerTest {
private Jedis jedis;
private TestRestTemplate testRestTemplate;
private TestRestTemplate testRestTemplateWithAuth;
private String testUrl = "http://localhost:8080/";
@Before
public void clearRedisData() {
testRestTemplate = new TestRestTemplate();
testRestTemplateWithAuth = new TestRestTemplate("admin", "password", null);
jedis = new Jedis("localhost", 6379);
jedis.flushAll();
}
}
Observe como estamos configurando esses dois clientes - o cliente HTTP e o cliente Redis. Obviamente, nesse ponto, o servidor (e Redis) devem estar em funcionamento - para que possamos nos comunicar com eles através desses testes.
Vamos começar testando seRedis está vazio:
@Test
public void testRedisIsEmpty() {
Set result = jedis.keys("*");
assertEquals(0, result.size());
}
Agora teste se nossa segurança retorna um 401 para solicitações não autenticadas:
@Test
public void testUnauthenticatedCantAccess() {
ResponseEntity result = testRestTemplate.getForEntity(testUrl, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
}
Em seguida, testamos seSpring Session está gerenciando nosso token de autenticação:
@Test
public void testRedisControlsSession() {
ResponseEntity result = testRestTemplateWithAuth.getForEntity(testUrl, String.class);
assertEquals("hello admin", result.getBody()); //login worked
Set redisResult = jedis.keys("*");
assertTrue(redisResult.size() > 0); //redis is populated with session data
String sessionCookie = result.getHeaders().get("Set-Cookie").get(0).split(";")[0];
HttpHeaders headers = new HttpHeaders();
headers.add("Cookie", sessionCookie);
HttpEntity httpEntity = new HttpEntity<>(headers);
result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class);
assertEquals("hello admin", result.getBody()); //access with session works worked
jedis.flushAll(); //clear all keys in redis
result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
//access denied after sessions are removed in redis
}
Primeiro, nosso teste confirma que nossa solicitação foi bem-sucedida usando as credenciais de autenticação de administrador.
Em seguida, extraímos o valor da sessão dos cabeçalhos de resposta e o usamos como autenticação na segunda solicitação. Validamos isso e, em seguida, limpamos todos os dados emRedis.
Por fim, fazemos outra solicitação usando o cookie da sessão e confirmamos que estamos desconectados. Isso confirma queSpring Session está gerenciando nossas sessões.
7. Conclusão
Spring Session é uma ferramenta poderosa para gerenciar sessões HTTP. Com nosso armazenamento de sessão simplificado para uma classe de configuração e algumas dependências Maven, agora podemos conectar vários aplicativos à mesma instânciaRedise compartilhar informações de autenticação.
Como sempre, você pode encontrar o código-fonteover on Github.