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

让我来详细讲解一下如何利用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日

相关文章

  • 浅析使用JDBC操作MySQL需要添加Class.forName(“com.mysql.jdbc.Driver”)

    JDBC是Java数据库连接的简称,它是Java中操作数据库的一种标准,可以通过它连接MySQL、Oracle、SQL Server等多种数据库。其中,使用JDBC操作MySQL时,必须要添加Class.forName(“com.mysql.jdbc.Driver”)语句。 添加Class.forName(“com.mysql.jdbc.Driver”)的原…

    Java 2023年6月16日
    00
  • Java 对 Properties 文件的操作详解及简单实例

    Java 对 Properties 文件的操作详解及简单实例 在Java中,Properties文件是一种常见的配置文件格式,通常用于编写和读取应用程序的配置信息和设置属性。Properties文件是一种文本文件,内容以”key=value”的形式存储,可以使用Java代码来读取和写入。 读取 Properties 文件 为了读取Properties文件,需…

    Java 2023年6月15日
    00
  • struts2开发流程及详细配置

    Struts2开发流程及详细配置 简介 Struts2是一种基于MVC设计模式的web框架,它是从Struts1框架升级而来。与Struts1相比,Struts2更加灵活、可扩展和易于使用。Struts2的开发流程涉及到安装、配置和实现。该攻略旨在帮助开发者了解Struts2框架的开发流程及详细配置。 开发流程 下面是Struts2的基本开发流程: 确认开发…

    Java 2023年5月20日
    00
  • spring @Conditional的使用与扩展源码分析

    让我为您详细介绍“spring @Conditional的使用与扩展源码分析”的攻略。 什么是spring @Conditional @Conditional 是 Spring 中一种条件注解,可以根据满足指定的条件来决定是否创建这个 Bean。例如,可以使用 @Conditional 注解,根据不同的环境条件或者配置来创建不同的 Bean 实例。@Cond…

    Java 2023年5月19日
    00
  • Java的Hibernate框架中Criteria查询使用的实例讲解

    Java的Hibernate框架中Criteria查询使用的实例讲解 Hibernate是一个强大的ORM(对象关系映射)框架,在Hibernate中,Criteria API是一个使用简单的标准API,它提供了在不检查语法的情况下动态构建查询的功能。本文将对Java的Hibernate框架中Criteria查询使用的实例进行讲解。 Criteria查询的基…

    Java 2023年5月19日
    00
  • Java的Struts框架中的主题模板和国际化设置

    Java的Struts框架中的主题模板和国际化设置提供了一套全局约束的方式来统一管理Web应用的界面样式和用户语言环境,本文将为您提供完整的攻略,包括如何设置和使用主题模板和国际化设置。 设置主题模板 在Struts框架中,使用主题模板可以方便地统一管理Web应用的界面样式,通过以下步骤可以设置主题模板: 1. 在struts.xml中进行配置 在strut…

    Java 2023年5月20日
    00
  • JavaWeb实现文件上传下载功能实例详解

    针对“JavaWeb实现文件上传下载功能实例详解”的完整攻略,我来为你做一个详细的讲解。 一、文件上传的实现过程 文件上传是指通过网页将文件传输到服务器的操作,它是Web应用程序中常见的功能之一。而JavaWeb开发环境中,要想实现文件上传,需要经过以下几个步骤: 1. 前端表单设计 在前端,我们需要添加一个input标签,并设置其type属性为file,用…

    Java 2023年5月20日
    00
  • js+ajax处理java后台返回的json对象循环创建到表格的方法

    下面是详细讲解 “js+ajax处理java后台返回的json对象循环创建到表格的方法”的完整攻略: 1. AJAX请求数据 首先,我们需要在前端页面中发送一个AJAX请求,向后台请求获取数据。可以通过以下代码将数据请求发送到服务器端: $.ajax({ type: "GET", url: "/api/getData"…

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