Guide de la session de printemps
1. Vue d'ensemble
Spring Session a pour objectif simple de libérer la gestion de session des limitations de la session HTTP stockée sur le serveur.
La solution facilite le partage des données de session entre services dans le cloud sans être lié à un seul conteneur (c'est-à-dire Matou). De plus, il prend en charge plusieurs sessions dans le même navigateur et envoie des sessions dans un en-tête.
Dans cet article, nous utiliseronsSpring Session pour gérer les informations d'authentification dans une application Web. Bien queSpring Session puisse conserver les données en utilisant JDBC, Gemfire ou MongoDB, nous utiliseronsRedis.
Pour une introduction àRedis, consultez l'article dethis.
2. Un projet simple
Commençons par créer un simple projetSpring Boot à utiliser comme base pour nos exemples de session plus tard:
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
Notre application fonctionne avecSpring Boot et le pom parent fournit des versions pour chaque entrée. La dernière version de chaque dépendance peut être trouvée ici:spring-boot-starter-security,spring-boot-starter-web,spring-boot-starter-test.
Ajoutons également quelques propriétés de configuration pour notre serveur Redis dansapplication.properties:
spring.redis.host=localhost
spring.redis.port=6379
3. Configuration de démarrage de printemps
Commençons par démontrer la configuration deSpring Session avec Boot.
Remarque: Vous n'avez pas besoin de remplir les sections 3 et 4. Choisissez-en un selon que vous utilisez ou nonSpring Boot pour configurerSpring Session.
3.1. Les dépendances
Ajoutez ces dépendances à notre projet:
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.session
spring-session
Nous utilisons le pom parent d'amorçage pour définir les versions ici. Il est donc garanti qu'elles fonctionneront avec nos autres dépendances. La dernière version de chaque dépendance peut être trouvée ici:spring-boot-starter-data-redis,spring-session.
3.2. Configuration de la session de printemps
Ajoutons maintenant une classe de configuration pourSpring Session:
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
}
4. Configuration de ressort standard (pas de démarrage)
Jetons également un coup d'œil à l'intégration et à la configuration desspring-session sans Spring Boot - juste avec Spring.
4.1. Les dépendances
Premièrement, si nous ajoutonsspring-session à un projet Spring standard, nous devrons définir explicitement:
org.springframework.session
spring-session
1.2.2.RELEASE
org.springframework.data
spring-data-redis
1.5.0.RELEASE
Les dernières versions de ces modules peuvent être trouvées ici:spring-session,spring-data-redis
4.2. Configuration de la session de printemps
Ajoutons maintenant une classe de configuration pourSpring Session:
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
Comme vous pouvez le voir, les différences sont minimes - nous devons maintenant définir explicitement notre beanJedisConnectionFactory - Boot le fait pour nous.
Dans les deux types,@EnableRedisHttpSession et l'extension deAbstractHttpSessionApplicationInitializer créeront et câbleront un filtre devant toute notre infrastructure de sécurité pour rechercher les sessions actives et remplir le contexte de sécurité à partir des valeurs stockées dansRedis .
Complétons maintenant cette application avec un contrôleur et la configuration de sécurité.
5. Configuration d'application
Accédez à notre fichier d’application principal et ajoutez un contrôleur:
@RestController
public class SessionController {
@RequestMapping("/")
public String helloAdmin() {
return "hello admin";
}
}
Cela nous donnera un point final à tester.
Ensuite, ajoutez notre classe de configuration de sécurité:
@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();
}
}
Ceci protège nos points de terminaison avec une authentification de base et configure un utilisateur avec lequel tester.
6. Test
Enfin, testons tout - nous allons définir ici un test simple qui va nous permettre de faire 2 choses:
-
consommer l'application web en direct
-
parler à Redis
Commençons par mettre les choses en place:
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();
}
}
Notez comment nous configurons ces deux clients - le client HTTP et le client Redis. Bien entendu, à ce stade, le serveur (et Redis) devrait être opérationnel et opérationnel afin de pouvoir communiquer avec eux via ces tests.
Commençons par tester queRedis est vide:
@Test
public void testRedisIsEmpty() {
Set result = jedis.keys("*");
assertEquals(0, result.size());
}
Maintenant, testons que notre sécurité retourne un 401 pour les requêtes non authentifiées:
@Test
public void testUnauthenticatedCantAccess() {
ResponseEntity result = testRestTemplate.getForEntity(testUrl, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
}
Ensuite, nous testons queSpring Session gère notre jeton d'authentification:
@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
}
Tout d'abord, notre test confirme que notre demande a abouti à l'aide des informations d'identification de l'authentification de l'administrateur.
Ensuite, nous extrayons la valeur de session des en-têtes de réponse et l’utilisons comme authentification dans notre deuxième requête. Nous validons cela, puis effaçons toutes les données enRedis.
Enfin, nous effectuons une autre demande à l'aide du cookie de session et confirmons que nous sommes déconnectés. Cela confirme queSpring Session gère nos sessions.
7. Conclusion
Spring Session est un outil puissant pour gérer les sessions HTTP. Avec notre stockage de session simplifié à une classe de configuration et quelques dépendances Maven, nous pouvons désormais connecter plusieurs applications à la même instance deRedis et partager les informations d'authentification.
Comme toujours, vous pouvez trouver le code sourceover on Github.