Spring Security 实现“记住我”功能及原理解析

yizhihongxing

下面是关于“Spring Security 实现‘记住我’功能及原理解析”的完整攻略。

1. Spring Security “记住我”功能原理

1.1 什么是“记住我”功能

“记住我”是指,在浏览器关闭后,再次打开浏览器后用户仍然不需要重新登录,直接就可以访问受保护的资源。这个功能在某些情况下非常方便,比如在家里用个人电脑访问自己的博客网站,不想每次都登录。

1.2 “记住我”功能的原理

“记住我”功能的实现原理是在用户第一次登录成功后,在服务器端生成一个 “remember-me" cookie。这个cookie中包含用户名、密码和一个过期时间。当用户再次访问该网站时,服务器可以根据“remember-me”cookie的信息来自动登录用户,而无需再次输入用户名和密码。

2. Spring Security “记住我”功能实现

2.1 配置记住我功能

要使用Spring Security提供的“记住我”功能,需要在Security配置类中进行如下配置:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // http请求的安全配置
        http
          .authorizeRequests()
              .antMatchers("/", "/home").permitAll()
              .anyRequest().authenticated()
              .and()
          .formLogin()
              .loginPage("/login")
              .permitAll()
              .and()
          .rememberMe()       // 开启remember me 功能
              .tokenValiditySeconds(60*60*24*7)   // token 的有效时间为一周
              .rememberMeParameter("remember-me")  // 设置前端的remember me 参数名
              .key("uniqueAndSecret")   // 存储cookie的key
              .and()
          .logout()
              .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // 用户名密码配置,这里使用内存来配置用户
        auth
          .inMemoryAuthentication()
              .withUser("user").password("{noop}password").roles("USER")
              .and()
              .withUser("admin").password("{noop}password").roles("USER", "ADMIN");
    }
}

2.2 在登录表单中添加“记住我”选项

你需要在登录表单中添加“记住我”选项,例如:

<form class="form-signin" action="/login" method="post">
    <h2 class="form-signin-heading">请登录</h2>
    <label for="inputEmail" class="sr-only">用户名</label>
    <input type="text" id="inputEmail" name="username" class="form-control" placeholder="用户名" required autofocus>
    <label for="inputPassword" class="sr-only">密码</label>
    <input type="password" id="inputPassword" name="password" class="form-control" placeholder="密码" required>
    <div class="checkbox mb-3">
        <label>
            <input type="checkbox" name="remember-me" value="true"> 记住我
        </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
</form>

2.3 添加“记住我”测试示例

当用户输入用户名和密码并勾选“记住我”选项后,Spring Security会在服务器端生成一个“remember-me”cookie并将其发送给客户端的浏览器。当浏览器再次访问该网站时,将自动以“remember-me”cookie中的信息来自动登录用户。

下面是一个简单的测试示例:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RememberMeTests {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testWithRememberMe() {
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));

        // 1. 发送登录表单请求并携带用户名密码和“记住我”选项
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("username", "admin");
        map.add("password", "password");
        map.add("remember-me", "true");
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
        ResponseEntity<String> response = restTemplate.postForEntity("/login", entity, String.class);
        // 此处断言登录成功并返回首页
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertTrue(response.getBody().contains("首页"));

        // 2. 第一次使用 remember-me Cookie 访问受保护的页面 '/admin',此处也应该返回首页
        headers.set("Cookie", response.getHeaders().getFirst("Set-Cookie"));
        ResponseEntity<String> response2 = restTemplate.exchange("/admin", HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertEquals(HttpStatus.OK, response2.getStatusCode());
        assertTrue(response2.getBody().contains("首页"));

        // 3. 第二次使用 remember-me Cookie 访问受保护的页面 '/admin',此处应该访问 '/admin' 页面
        ResponseEntity<String> response3 = restTemplate.exchange("/admin", HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertEquals(HttpStatus.OK, response3.getStatusCode());
        assertTrue(response3.getBody().contains("管理员页面"));
    }
}

2.4 添加“记住我”自动登录失败的测试示例

如果remember-me cookie已过期或者用户名和密码已经变更,则remember me功能验证将不会通过,为了验证这一点,下面是一个自动登录失败的测试示例:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RememberMeFailureTests {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testWithRememberMe() {
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));

        // 1. 发送带 remember-me 选项的登录表单,登录成功且生成 cookie
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("username", "admin");
        map.add("password", "password");
        map.add("remember-me", "true");
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
        ResponseEntity<String> response = restTemplate.postForEntity("/login", entity, String.class);
        // 此处断言登录成功并返回首页
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertTrue(response.getBody().contains("首页"));

        // 2. 删除 '/admin' 中登录后,由 remember me 产生的 session 属性
        headers.set("Cookie", response.getHeaders().getFirst("Set-Cookie"));
        restTemplate.execute("/admin", HttpMethod.DELETE, null, null);

        // 3. 第一次使用 remember-me Cookie 访问 '/admin',此处应该访问登录页
        ResponseEntity<String> response2 = restTemplate.exchange("/admin", HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertEquals(HttpStatus.OK, response2.getStatusCode());
        assertTrue(response2.getBody().contains("请登录"));

        // 4. 第二次使用 remember-me Cookie 访问 '/admin',此处也应该访问登录页
        ResponseEntity<String> response3 = restTemplate.exchange("/admin", HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertEquals(HttpStatus.OK, response3.getStatusCode());
        assertTrue(response3.getBody().contains("请登录"));
    }
}

以上就是关于Spring Security实现“记住我”功能及原理解析的完整攻略,具体请参考代码示例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security 实现“记住我”功能及原理解析 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • 浅谈Java当作数组的几个应用场景

    浅谈Java当作数组的几个应用场景 Java 数组是一个容器,可以存储一定数量的数据,Java 数组可以包含基本类型(int、short、long、byte、float、double、boolean、char)和引用类型(类、接口、数组)。 Java 数组可以作为各种数据结构的基础,介绍几个 Java 数组的应用场景。 1. 用 Java 数组模拟队列 队列…

    Java 2023年5月26日
    00
  • vue.js数据响应式原理解析

    Vue.js数据响应式原理解析 Vue.js是一个极易上手,功能强大的Javascript框架,它的核心就是数据响应式系统。在Vue.js中,我们可以轻松的绑定数据和视图,而这一切都得益于Vue.js的数据响应式系统。在本篇文章中,我们将深入剖析Vue.js数据响应式原理。 数据响应式系统란? Vue.js的数据响应式系统简单来说,就是一种将ViewMode…

    Java 2023年5月23日
    00
  • Java Apache Commons报错“IllegalArgumentException”的原因与解决方法

    当使用Java的Apache Commons类库时,可能会遇到“IllegalArgumentException”错误。这个错误通常由以下原因之一起: 参数错误:如果参数错误,则可能会出现此错误。在这种情况下,需要检查参数以解决此问题。 方法调用错误:如果方法调用错误,则可能会出现此错误。在这种情况下,需要检查方法调用以解决此问题。 以下是两个实例: 例1 …

    Java 2023年5月5日
    00
  • Java 超详细讲解异常的处理

    Java 超详细讲解异常的处理 什么是异常? 在 Java 中,异常指的是程序在运行过程中发生了意外情况或错误,导致程序无法继续运行的情况。比如数组访问越界、空指针等。 异常的分类 在 Java 中,异常分为两类:受检异常和非受检异常。 受检异常(Checked Exception) 受检异常指的是在编译时就能够发现的异常,需要在代码中显式的进行处理。比如读…

    Java 2023年5月19日
    00
  • java后台如何利用Pattern提取所需字符详解

    下面就是关于“Java后台如何利用Pattern提取所需字符”的完整攻略: 1. 基本概念 在Java中,正则表达式的使用非常重要,而Pattern类就是Java中正则表达式的核心类,用于解析和匹配正则表达式。下面是Pattern类中最基本的方法: public static Pattern compile(String regex) public Matc…

    Java 2023年5月27日
    00
  • 深度思考JDK8中日期类型该如何使用详解

    深度思考JDK8中日期类型该如何使用详解 JDK8引入了新的日期和时间API,旨在取代原先的Date和Calendar类。新的API提供了更好的易用性和可读性,同时也更加严格和健壮。在使用时间和日期时,应该尽量使用新的API。 LocalDate LocalDate是新API中表示日期的主要类。它是一个不可变的类,用于表示ISO-8601日历系统中的日期(年…

    Java 2023年5月20日
    00
  • 如何检查线程状态?

    以下是关于如何检查线程状态的完整使用攻略: 如何检查线程状态? 在 Java 中,可以使用 Thread 类的 getState() 方法来获取线程的状态。该方法返回一个 Thread.State 枚举类型的值,表示线程的状态。 示例一:使用 getState() 方法获取线程状态。可以使用以下代码实现: public class MyThread exte…

    Java 2023年5月12日
    00
  • Spring Boot 入门之消息中间件的使用

    消息中间件是一种常用的分布式系统解决方案,可以帮助不同的应用程序之间进行异步通信。在Spring Boot中,可以使用Spring Boot提供的集成库来方便地使用消息中间件。在本文中,我们将详细讲解Spring Boot入门之消息中间件的使用,并提供两个示例来演示如何使用消息中间件。 Spring Boot入门之消息中间件的使用 以下是使用消息中间件的基本…

    Java 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部