Spring Security 构建rest服务实现rememberme 记住我功能

yizhihongxing

让我来详细讲解一下如何利用Spring Security构建REST服务实现记住我(remember-me)功能。

什么是记住我功能?

记住我是一个常见的Web应用程序功能,允许用户在关闭并重新打开浏览器后继续使用应用程序而无需重新登录。通常,当用户登录时,他们可以选择“记住我”选项。如果选中此选项,则应用程序将在用户关闭并重新打开浏览器时,使用之前提供的凭据进行自动登录。

实现过程

下面将分为5步来实现Spring Security的记住我功能。

1. 添加Spring Security依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 配置Spring Security

在这一步中,需要配置Spring Security。首先,要启用remember-me功能:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/login**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe(); // 启用remember-me功能
    }
}

上述代码通过rememberMe()启用了Spring Security的remember-me功能。这将启用Cookie的自动创建和使用,以保存已认证的用户之间的状态。

3. 配置“记住我”参数

Spring Security提供了以下“记住我”参数的配置:

  • key:用于加密令牌的密钥,必须是16个字符以上的字符串。
  • tokenValiditySeconds:令牌的有效期,以秒为单位。默认为2周。
  • rememberMeParameter:处理“记住我”请求的参数名。默认为"remember-me"。
  • rememberMeCookieName:用于保存令牌的Cookie的名称。默认为“remember-me”。
  • useSecureCookie:设置是否只发送安全Cookie。默认为false。
  • alwaysRemember:设置是否始终发送“记住我”Cookie,而不是在默认的会话Cookie上添加一个属性。默认为false。

你可以通过rememberMe()方法进行配置:

http
    .rememberMe()
        .key("my-remember-me-key")
        .tokenValiditySeconds(86400) // 一天
        .rememberMeParameter("remember-me")
        .rememberMeCookieName("my-remember-me-cookie")
        .useSecureCookie(true)
        .alwaysRemember(true);

4. 编写登录页面和登录处理程序

在登录页面中包含一个复选框,用户可以使用该复选框选择是否记住他们的登录信息。在登录处理程序中,将使用用户名、密码和remember-me参数来进行身份验证。

以下是一个简单的登录页面和应用程序的登录处理程序:

<html>
    <body>
        <h2>Login</h2>
        <form action="/login" method="post">
            <p>
                <label for="username">Username:</label>
                <input type="text" id="username" name="username"/>
            </p>

            <p>
                <label for="password">Password:</label>
                <input type="password" id="password" name="password"/>
            </p>

            <p>
                <label for="remember-me">Remember me:</label>
                <input type="checkbox" id="remember-me" name="remember-me"/>
            </p>

            <input type="submit" value="Submit"/>
        </form>
    </body>
</html>
@Controller
public class LoginController {

    @GetMapping("/login")
    public String showLoginPage() {
        return "login";
    }

    @PostMapping("/login")
    public String login(HttpServletRequest request, HttpServletResponse response) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String rememberMe = request.getParameter("remember-me");

        if (username.equals("admin") && password.equals("password")) {
            // 如果成功验证,则创建一个remember-me Cookie
            String rememberMeToken = UUID.randomUUID().toString();
            Cookie rememberMeCookie = new Cookie("remember-me", rememberMeToken);
            rememberMeCookie.setPath("/");
            if (rememberMe != null && rememberMe.equals("on")) {
                rememberMeCookie.setMaxAge(60 * 60 * 24 * 30); // 一个月
            } else {
                rememberMeCookie.setMaxAge(0);
            }
            response.addCookie(rememberMeCookie);
            return "success";
        } else {
            return "error";
        }
    }
}

在上述代码中,login()方法将根据提供的用户名和密码进行身份验证。如果验证成功,则创建一个新的记住我Cookie,并将其添加到HTTP响应中。

5. 验证记住我功能是否正常

在每次访问应用程序时,Spring Security将使用保存在Cookie中的信息来自动登录用户。你可以使用类似于以下Java代码的方法验证它是否正常工作:

public void authenticateWithCookie() {
    RestTemplate restTemplate = new RestTemplate();

    // 创建一个HTTP头,包含一个"remember-me" Cookie
    HttpHeaders headers = new HttpHeaders();
    headers.set("Cookie", "remember-me=my-remember-me-token");

    // 调用受Spring Security保护的REST服务
    ResponseEntity<String> response = restTemplate.exchange(
        "http://localhost:8080/protected",
        HttpMethod.GET,
        new HttpEntity<String>(headers),
        String.class);
    String responseBody = response.getBody();
    System.out.println(responseBody);
}

这个方法将创建一个HTTP头,其中包含一个记住我Cookie。然后,它将调用受Spring Security保护的REST服务,以验证该Cookie是否有效。

示例

示例一:基础REST服务

首先,我们创建一个名为“demo”的Spring Boot项目,并在其中添加以下依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

接下来,我们可以创建一个名为“HelloController”的REST服务:

@RestController
public class HelloController {

    @GetMapping("/")
    public String hello() {
        return "Hello, world!";
    }

    @GetMapping("/protected")
    public String protectedEndpoint() {
        return "This is a protected endpoint!";
    }
}

这将为根路径和受保护的路径提供REST服务。

现在,我们可以在Spring Security配置文件中启用记住我功能:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/login**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe();
    }
}

最后,在“login.html”的编写包含“记住我”复选框的登录页面:

<html>
    <body>
        <h2>Login</h2>
        <form action="/login" method="post">
            <p>
                <label for="username">Username:</label>
                <input type="text" id="username" name="username"/>
            </p>

            <p>
                <label for="password">Password:</label>
                <input type="password" id="password" name="password"/>
            </p>

            <p>
                <label for="remember-me">Remember me:</label>
                <input type="checkbox" id="remember-me" name="remember-me"/>
            </p>

            <input type="submit" value="Submit"/>
        </form>
    </body>
</html>

我们的示例一完成了!你现在可以启动应用程序并进行测试。

示例二:用户名密码都存储在数据库

我们还可以使用JDBC存储用户名和密码。首先,我们需要在pom.xml中添加以下依赖项:

<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
</dependencies>

接下来,我们可以在application.properties中配置我们的数据源:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=create-drop

最后,在Spring Security配置文件中稍作修改:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/login**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe()
                .tokenRepository(persistentTokenRepository()) // 设定tokenRepository
                .tokenValiditySeconds(200000); // 设定token有效期

    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery(
                        "SELECT username, password, enabled FROM users WHERE username=?")
                .authoritiesByUsernameQuery(
                        "SELECT username, authority FROM authorities WHERE username=?")
                .passwordEncoder(new BCryptPasswordEncoder());
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }
}

在这里,我们使用tokenRepository()方法将JdbcTokenRepositoryImpl注入到Spring Security中。这个类是可以持久化记住我的Token的,其默认的数据库表结构是:

CREATE TABLE `persistent_logins` (
  `username` varchar(64) NOT NULL,
  `series` varchar(64) NOT NULL,
  `token` varchar(64) NOT NULL,
  `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`series`)
);

最后,我们需要创建一些用户并赋予权限以供测试。

示例完整代码请参见:https://github.com/Bright-Sky/Spring-Security-Demo。

总结

在本篇文章中,我们讲解了如何使用Spring Security构建Rest服务实现“记住我”(remember-me)功能。我们通过示例说明如何启动基本的REST服务,并使用JDBC存储用户名和密码。如果你想了解更多有关Spring Security的内容,请访问官方文档:https://spring.io/projects/spring-security。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security 构建rest服务实现rememberme 记住我功能 - Python技术站

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

相关文章

  • Java工厂模式用法之如何动态选择对象详解

    Java工厂模式用法之如何动态选择对象详解 工厂模式简介 在软件开发中经常需要创建对象,由于创建对象过程比较复杂,因此我们通常利用工厂模式来创建对象。工厂模式是指定义一个用于创建对象的接口(工厂接口),由实现这个接口的类(具体工厂)来创建具体的对象(产品)。在工厂模式中,客户端不直接 new 一个类的实例,而是通过工厂接口来创建实例,从而将实例的创建和使用代…

    Java 2023年5月26日
    00
  • JDBC中resutset接口操作实例详解

    JDBC中ResultSet接口操作实例详解 一、ResultSet简介 ResultSet接口是Java程序中访问数据库返回的数据的一个接口,通过该接口我们可以对返回的数据进行操作。该接口在JDBC规范中属于处理查询结果的API,我们可以通过该接口获取到查询结果集中所有的行信息并且可以从结果集中获取指定行列的数据。 下面我们将通过示例讲解ResultSet…

    Java 2023年6月16日
    00
  • Myeclipse中hibernate自动创建表的方法

    下面是MyEclipse中Hibernate自动创建表的方法的完整攻略。 准备工作 在MyEclipse中安装Hibernate插件 在MyEclipse中创建Java工程 导入Hibernate相关的jar包 配置Hibernate的配置文件hibernate.cfg.xml 使用Hibernate自动创建表 在实体类中添加@Table、@Column等注…

    Java 2023年5月20日
    00
  • java实现联机五子棋

    Java实现联机五子棋完整攻略 引言 联机五子棋是一种经典的、非常受欢迎的棋类游戏。在实现联机五子棋游戏过程中,需要采用 Java编程语言 进行设计和开发。本文将为您提供一份完整的攻略,指导您如何使用 Java实现联机五子棋游戏。 前置技能 在开始实现联机五子棋游戏前,我们需要掌握以下技能: 掌握 Java编程语言 ; 对 Java I/O相关API的使用必…

    Java 2023年5月19日
    00
  • 东八区springboot如何配置序列化

    下面是详细讲解“东八区SpringBoot如何配置序列化”的攻略。 1、序列化概念简述 Java中的序列化是指将一个Java对象转化为字节流,这样可以将对象存储在磁盘上或通过网络传输。而反序列化则是将字节流转化为对象。 在Spring Boot中,对象的序列化往往用于将对象作为响应返回给客户端或者使用Redis等缓存技术进行存储。 2、Spring Boot…

    Java 2023年5月20日
    00
  • 微信小程序组件化开发的实战步骤

    下面我会详细讲解“微信小程序组件化开发的实战步骤”的完整攻略,共分为以下几个步骤: 1. 创建自定义组件 首先,在小程序项目中新建一个文件夹,用来存放自定义组件。命名可以根据需要自行定义,这里以 components 为例。在文件夹中按照组件的需求创建各个组件文件夹,比如 toast(提示框组件)、modal(弹框组件)等。 在组件文件夹中,需要新建三个文件…

    Java 2023年5月23日
    00
  • STRUTS+AJAX+JSP 请求到后台乱码问题解决方法

    针对 “STRUTS+AJAX+JSP 请求到后台乱码问题解决方法” 这个问题,我们需要分几个步骤来进行讲解。 步骤一:字符集设置 在 web.xml 文件中配置字符集编码为 UTF-8,以支持中文等特殊字符的传输。 <web-app> <filter> <filter-name>encodingFilter</fi…

    Java 2023年6月15日
    00
  • Java过滤器与监听器间区别与联系

    Java过滤器与监听器的区别和联系 本文主要讲解Java Web中过滤器和监听器的区别和联系。过滤器(Filter)和监听器(Listener)都可以通过Web.xml进行配置,并且也可以通过注解的方式进行配置。 过滤器(Filter) 过滤器是在请求被处理之前对http请求和response进行预处理的技术,它可以拦截客户端发送的请求和服务器返回的响应,同…

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