搜公众号
推荐 原创 视频 Java开发 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库
Lambda在线 > spring之session

spring之session

2018-12-16
举报
spring之session

1概述


    Spring Session的目标是从存储在服务器中的HTTP会话的限制中释放会话管理。

    该解决方案可以轻松地在独立部署的服务之间共享会话数据,而不必绑定到单个容器(即Tomcat)。 此外,它支持在同一浏览器中的多个会话并在标头中发送会话。

    在本文中,我们将使用Spring Session来管理Web应用程序中的身份验证信息。 虽然Spring Session可以使用JDBC或MongoDB来持久保存数据,但我们将使用Redis。

2简单项目案例


    首先创建一个简单的Spring Boot项目,方便在后边的会话示例中使用:

  1. <parent>

  2.    <groupId>org.springframework.boot</groupId>

  3.    <artifactId>spring-boot-starter-parent</artifactId>

  4.    <version>2.0.5.RELEASE</version>

  5.    <relativePath/>

  6. </parent>

  7. <dependencies>

  8.    <dependency>

  9.        <groupId>org.springframework.boot</groupId>

  10.        <artifactId>spring-boot-starter-security</artifactId>

  11.    </dependency>

  12.    <dependency>

  13.        <groupId>org.springframework.boot</groupId>

  14.        <artifactId>spring-boot-starter-web</artifactId>

  15.    </dependency>

  16.    <dependency>

  17.        <groupId>org.springframework.boot</groupId>

  18.        <artifactId>spring-boot-starter-test</artifactId>

  19.        <scope>test</scope>

  20.    </dependency>

  21. </dependencies>  

    我们的应用程序使用Spring Boot运行,父pom为每个条目提供版本。 可以在Maven中心仓库找到每个依赖项的最新版本。

    还需要在application.properties中为我们的Redis服务器添加一些配置属性:

  1. spring.redis.database=0

  2. spring.redis.host=host

  3. spring.redis.port=6379

  4. spring.redis.password=password  

3springboot配置


    首先,演示使用Boot配置Spring Session。

    注意:不需要完成第3节和第4节。只需选择一个,具体取决于您是否使用SpringBoot配置Spring Session。

3.1:依赖管理

    添加以下依赖到我们的项目中:

  1. <dependency>

  2.    <groupId>org.springframework.boot</groupId>

  3.    <artifactId>spring-boot-starter-data-redis</artifactId>

  4. </dependency>

  5. <dependency>

  6.    <groupId>org.springframework.session</groupId>

  7.    <artifactId>spring-session</artifactId>

  8. </dependency>    

    我们使用启动父pom在这里设置版本,因此这些版本可以保证与我们的其他依赖项一起使用。

3.2:Spring会话配置

    现在为Spring Session添加一个配置类:

  1. @Configuration

  2. @EnableRedisHttpSession

  3. public class SessionConfig extends AbstractHttpSessionApplicationInitializer {

  4. }

4标准spring配置(不使用springboot)


    我们看一下不使用Spring Boot,使用传统方式实现spring集成和配置spring-session。 

4.1:依赖管理

    首先,如果我们将spring-session添加到标准的Spring项目中,我们需要明确定义:

  1. <dependency>

  2.    <groupId>org.springframework.session</groupId>

  3.    <artifactId>spring-session</artifactId>

  4.    <version>1.2.2.RELEASE</version>

  5. </dependency>

  6. <dependency>

  7.    <groupId>org.springframework.data</groupId>

  8.    <artifactId>spring-data-redis</artifactId>

  9.    <version>2.0.5.RELEASE</version>

  10. </dependency>  


4.2:spring session配置

    现在为Spring Session添加一个配置类:

  1. @Configuration

  2. @EnableRedisHttpSession

  3. public class SessionConfig extends AbstractHttpSessionApplicationInitializer {

  4.    @Bean

  5.    public JedisConnectionFactory connectionFactory() {

  6.        return new JedisConnectionFactory();

  7.    }

  8. }    

    正如你所看到的最小差异-我们现在必须明确定义JedisConnectionFactory bean,而SpringBoot帮我们做了。  

    在两种类型中,@EnableRedisHttpSession和AbstractHttpSessionApplicationInitializer的扩展实现,将在所有安全基础结构之前创建并连接一个过滤器,

    用以查找活跃会话,并用存储在Redis中的值来填充安全上下文。

    接下来我们用控制器和安全配置来完成这个应用程序。 

5应用配置


     添加一个控制器:

  1. @RestController

  2. public class SessionController {

  3.    @RequestMapping("/")

  4.    public String helloAdmin() {

  5.        return "hello admin";

  6.    }

  7. }    

    这个控制器为我们提供一个测试端点。

    接下来,添加我们的安全配置类:

  1. @Configuration

  2. @EnableWebSecurity

  3. public class SecurityConfig extends WebSecurityConfigurerAdapter {

  4.    @Autowired

  5.    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

  6.        auth

  7.          .inMemoryAuthentication()

  8.          .withUser("admin").password("password").roles("ADMIN");

  9.    }

  10.    @Override

  11.    protected void configure(HttpSecurity http) throws Exception {

  12.        http

  13.          .httpBasic().and()

  14.          .authorizeRequests()

  15.          .antMatchers("/").hasRole("ADMIN")

  16.          .anyRequest().authenticated();

  17.    }

  18. }    

    这可以通过基本身份验证保护我们的端点,并设置要测试的用户。


6测试


    最后,对上述内容进行测试,我们将在这里定义一个简单的测试,这将允许我们做两件事:

  • 使用实时Web应用程序

  • 与Redis交互

    测试准备:   

  1. public class SessionControllerTest {

  2.    private Jedis jedis;

  3.    private TestRestTemplate testRestTemplate;

  4.    private TestRestTemplate testRestTemplateWithAuth;

  5.    private String testUrl = "http://localhost:8080/";

  6.    @Before

  7.    public void clearRedisData() {

  8.        testRestTemplate = new TestRestTemplate();

  9.        testRestTemplateWithAuth = new TestRestTemplate("admin", "password", null);

  10.        jedis = new Jedis("host", 6379);

  11.        jedis.flushAll();

  12.    }

  13. }  

    需要注意的是,我们如何设置这两个客户端-HTTP客户端和Redis客户端。 当然,此时服务器(和Redis)应该启动并运行-这样我们就可以通过这些测试与它们进行通信。

    从测试Redis是空的开始:  

  1. @Test

  2. public void testRedisIsEmpty() {

  3.    Set<String> result = jedis.keys("*");

  4.    assertEquals(0, result.size());

  5. }  

    现在测试我们的安全保护为未经身份验证的请求返回401: 

  1. @Test

  2. public void testUnauthenticatedCantAccess() {

  3.    ResponseEntity<String> result = testRestTemplate.getForEntity(testUrl, String.class);

  4.    assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());

  5. }    

    接下来,我们测试Spring Session是否在管理我们的身份验证令牌: 

  1. @Test

  2. public void testRedisControlsSession() {

  3.    ResponseEntity<String> result = testRestTemplateWithAuth.getForEntity(testUrl, String.class);

  4.    assertEquals("hello admin", result.getBody()); //login worked

  5.    Set<String> redisResult = jedis.keys("*");

  6.    assertTrue(redisResult.size() > 0); //redis is populated with session data

  7.    String sessionCookie = result.getHeaders().get("Set-Cookie").get(0).split(";")[0];

  8.    HttpHeaders headers = new HttpHeaders();

  9.    headers.add("Cookie", sessionCookie);

  10.    HttpEntity<String> httpEntity = new HttpEntity<>(headers);

  11.    result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class);

  12.    assertEquals("hello admin", result.getBody()); //access with session works worked

  13.    jedis.flushAll(); //clear all keys in redis

  14.    result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class);

  15.    assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());

  16.    //access denied after sessions are removed in redis

  17. }    

    首先,我们的测试使用管理员身份验证凭据确认我们的请求成功。

    然后我们从响应头中提取会话值,并在第二个请求中将其用作我们的身份验证。 验证之后清除Redis中的所有数据。

    最后,我们使用会话cookie发出另一个请求并确认已注销。 这证实了Spring Session正在管理我们的会话。  

总结

    Spring Session是一个用于管理HTTP会话的强大工具。 通过将会话存储简化为配置类和几个Maven依赖项,我们现在可以将多个应用程序连接到同一个Redis实例并共享身份验证信息。  

    比如为了应对高并发请求,应用集群部署,那么应用的多个部署实例可以共享同一份session信息。


版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《spring之session》的版权归原作者「PersistentCoder」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注PersistentCoder微信公众号

PersistentCoder微信公众号:TyphoonChan

PersistentCoder

手机扫描上方二维码即可关注PersistentCoder微信公众号

PersistentCoder最新文章

精品公众号随机推荐

举报