Guide de la session de printemps

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.