Springboot实现邮箱验证码注册与修改密码及登录功能详解流程

Springboot实现邮箱验证码注册与修改密码及登录功能详解流程

1. 准备工作

1.1 导入依赖

pom.xml 文件中导入以下依赖:

<!-- Spring Boot -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Data JPA -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- JDBC驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- 邮箱发送 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

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

<!-- Thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- Validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

1.2 配置文件

application.yml 文件中配置数据库、邮箱、安全等相关信息。

2. 实现激活码注册功能

2.1 用户实体类设计

com.example.entity 包下创建 User 实体类:

@Entity
@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotBlank(message = "用户名不能为空")
    private String username;

    @NotBlank(message = "密码不能为空")
    private String password;

    @Email(message = "邮箱格式不正确")
    private String email;

    @NotNull(message = "激活状态不能为空")
    private Boolean activated = false;

    // getter、setter 省略
}

2.2 用户注册页面设计

resources/templates 目录下创建 register.html 页面(使用 Thymeleaf 模板引擎):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>注册</title>
</head>
<body>
    <h1>注册</h1>

    <form method="post" action="/register">
        <label for="email">邮箱:</label>
        <input type="email" name="email" id="email" required />
        <br/>

        <label for="username">用户名:</label>
        <input type="text" name="username" id="username" required />
        <br/>

        <label for="password">密码:</label>
        <input type="password" name="password" id="password" required />
        <br/>

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

2.3 注册控制器设计

com.example.controller 包下创建 UserController 控制器:

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    private MailSenderService mailSenderService;

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

    @PostMapping("/register")
    public String register(@Valid User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return "register";
        }

        // 判断邮箱是否已注册
        if (userService.findByEmail(user.getEmail()) != null) {
            bindingResult.rejectValue("email", null, "该邮箱已注册");
            return "register";
        }

        // 生成随机激活码
        String activationCode = RandomStringUtils.randomAlphabetic(10);

        // 保存用户到数据库
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        user.setActivated(false);
        user = userService.save(user);

        // 发送邮件
        mailSenderService.sendActivationMail(user.getEmail(), activationCode);

        return "redirect:/activate?email=" + user.getEmail();
    }

    @GetMapping("/activate")
    public String activate(String email, String activationCode, Model model) {
        User user = userService.findByEmail(email);

        if (user == null) {
            model.addAttribute("errorMsg", "用户不存在");
        } else if (user.getActivated()) {
            model.addAttribute("errorMsg", "用户已激活");
        } else if (StringUtils.equals(activationCode, user.getActivationCode())) {
            user.setActivated(true);
            userService.save(user);
            model.addAttribute("successMsg", "激活成功");
        } else {
            model.addAttribute("errorMsg", "激活码不正确");
        }

        return "activate";
    }
}

2.4 邮件发送服务设计

com.example.service 包下创建 MailSenderService 邮件发送服务:

@Service
public class MailSenderService {
    @Autowired
    private JavaMailSender mailSender;

    public void sendActivationMail(String email, String activationCode) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("your@mail.com"); // 发件人邮箱
        message.setTo(email); // 收件人邮箱
        message.setSubject("激活账号"); // 邮件主题
        message.setText("请点击链接进行激活:http://localhost:8080/activate?email=" + email + "&activationCode=" + activationCode); // 邮件内容
        mailSender.send(message);
    }
}

3. 实现修改密码功能

3.1 修改密码页面设计

resources/templates 目录下创建 reset_password.html 页面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>修改密码</title>
</head>
<body>
    <h1>修改密码</h1>

    <form method="post" action="/reset_password">
        <input type="hidden" name="token" value="[[$token]]" />

        <label for="password">新密码:</label>
        <input type="password" name="password" id="password" required />
        <br/>

        <input type="submit" value="修改密码" />
    </form>
</body>
</html>

3.2 修改密码控制器设计

com.example.controller 包下创建 PasswordResetController 控制器:

@Controller
public class PasswordResetController {
    @Autowired
    private PasswordResetTokenService tokenService;

    @Autowired
    private UserService userService;

    @GetMapping("/forgot_password")
    public String forgotPassword() {
        return "forgot_password";
    }

    @PostMapping("/forgot_password")
    public String forgotPassword(String email, Model model) {
        User user = userService.findByEmail(email);

        if (user == null) {
            model.addAttribute("errorMsg", "用户不存在");
        } else {
            tokenService.createToken(user);
            model.addAttribute("successMsg", "已发送邮件,请查收");
        }

        return "forgot_password";
    }

    @GetMapping("/reset_password_token")
    public String resetPasswordToken(String token, Model model) {
        PasswordResetToken resetToken = tokenService.findByToken(token);

        if (resetToken == null) {
            model.addAttribute("errorMsg", "重置密码链接已失效");
            return "reset_password_result";
        }

        if (resetToken.isExpired()) {
            model.addAttribute("errorMsg", "重置密码链接已过期");
            return "reset_password_result";
        }

        model.addAttribute("token", token);
        return "reset_password";
    }

    @PostMapping("/reset_password")
    public String resetPassword(String token, String password, Model model) {
        PasswordResetToken resetToken = tokenService.findByToken(token);

        if (resetToken == null) {
            model.addAttribute("errorMsg", "重置密码链接已失效");
            return "reset_password_result";
        }

        if (resetToken.isExpired()) {
            model.addAttribute("errorMsg", "重置密码链接已过期");
            return "reset_password_result";
        }

        User user = resetToken.getUser();
        user.setPassword(new BCryptPasswordEncoder().encode(password));
        userService.save(user);

        model.addAttribute("successMsg", "修改密码成功");
        return "reset_password_result";
    }
}

3.3 重置密码实体类设计

com.example.entity 包下创建 PasswordResetToken 实体类:

@Entity
@Table(name = "t_password_reset_token")
public class PasswordResetToken {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Column(unique = true)
    private String token;

    @NotNull
    private Date expiryDate;

    // getter、setter 省略
}

3.4 重置密码服务设计

com.example.service 包下创建 PasswordResetTokenService 重置密码服务:

@Service
public class PasswordResetTokenService {
    @Autowired
    private PasswordResetTokenRepository tokenRepository;

    public PasswordResetToken createToken(User user) {
        PasswordResetToken token = new PasswordResetToken();
        token.setUser(user);
        token.setToken(UUID.randomUUID().toString());
        token.setExpiryDate(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000)); // 设置为 24 小时后过期
        return tokenRepository.save(token);
    }

    public PasswordResetToken findByToken(String token) {
        return tokenRepository.findByToken(token);
    }
}

4. 实现登录功能

4.1 登录控制器设计

com.example.controller 包下创建 SecurityController 控制器:

@Controller
public class SecurityController {
    @GetMapping("/login")
    public String login() {
        return "login";
    }

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

4.2 安全配置类设计

com.example.config 包下创建 SecurityConfig 安全配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserService userService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/register", "/activate/**", "/forgot_password", "/reset_password_token/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .defaultSuccessUrl("/")
                .and()
            .logout()
                .permitAll();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

5. 示例说明

5.1 注册账号

  1. 访问注册页面:http://localhost:8080/register
  2. 输入邮箱、用户名和密码,点击注册按钮
  3. 到注册邮箱收取激活邮件,并点击邮件里的激活链接
  4. 成功激活后,页面跳转到主页

5.2 忘记密码

  1. 访问忘记密码页面:http://localhost:8080/forgot_password
  2. 输入邮箱,点击发送重置密码邮件
  3. 到注册邮箱收取重置密码邮件,并点击邮件里的重置密码链接
  4. 进入重置密码页面,输入新密码并保存
  5. 成功修改密码后,页面跳转到重置密码结果页面

5.3 登录

  1. 访问登录页面:http://localhost:8080/login
  2. 输入已注册的用户的账号密码,点击登录按钮
  3. 成功登录后,页面跳转到主页

结语

本文详细讲解了如何使用 Spring Boot 实现邮箱验证码注册与修改密码及登录功能,主要包括用户实体类设计、邮箱发送、注册控制器设计、重置密码实体类设计、重置密码服务设计、登录控制器设计以及安全配置类设计。通过本文的学习,可以快速掌握这些功能的实现流程,有助于提高开发效率。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot实现邮箱验证码注册与修改密码及登录功能详解流程 - Python技术站

(0)
上一篇 2023年6月11日
下一篇 2023年6月11日

相关文章

  • JS事件循环机制event loop宏任务微任务原理解析

    接下来我会详细讲解一下JS事件循环机制(event loop)、宏任务和微任务的原理,以及该如何理解它们之间的关系。 1. 事件循环机制(event loop)的原理 在JavaScript中,事件循环机制定义了一种代码执行模型,可以控制代码在何时执行。事件循环机制主要分为以下两个部分: 执行栈(Execution Context Stack) 任务队列(T…

    JavaScript 2023年6月11日
    00
  • 浅谈js中的三种继承方式及其优缺点

    下面我来详细讲解一下 “浅谈js中的三种继承方式及其优缺点” 的完整攻略。 一、继承的基本概念 继承是面向对象编程中的一个重要概念,它允许新建的对象自动获取某个现有对象的属性和方法。在 JavaScript 中,继承主要有以下三种方式。 二、原型链继承 原型链继承是 JavaScript 中最常用的继承方式之一,其基本思想是利用原型让一个引用类型继承另外一个…

    JavaScript 2023年6月11日
    00
  • THREE.JS入门教程(2)着色器-上

    《THREE.JS入门教程(2)着色器-上》是一篇介绍Three.js着色器的教程,包含了以下内容: 着色器的基本概念:该部分介绍了着色器的概念、类型(顶点着色器和片元着色器)、编写方式等基本知识点。 Three.js内置着色器介绍:该部分介绍了Three.js内置的着色器,包括BasicShader、LambertShader、PhongShader和To…

    JavaScript 2023年6月10日
    00
  • JavaScript window.setTimeout() 的详细用法

    JavaScript window.setTimeout() 的详细用法 在 JavaScript 中,window.setTimeout() 方法可以定时执行一个指定的代码块。它接收两个参数,分别是需要执行的代码块和执行时间(单位为毫秒)。 语法 window.setTimeout(code, delay); 其中,code 为需要执行的代码块;delay…

    JavaScript 2023年6月11日
    00
  • javascript之对系统的toFixed()方法的修正

    前言: 在 Javascript 中,toFixed() 方法可以将一个数字保留指定位数的小数。但是这个方法存在一个问题,对于某些数字在小数部分保留时可能会出现精度错误。本文将介绍如何修正toFixed()方法在某些情况下出现的精度错误。 修正toFixed()方法的代码: 我们将修正后的代码命名为toFixedNew()方法。toFixedNew()方法可…

    JavaScript 2023年6月10日
    00
  • javascript写的日历类(基于pj)

    这里是“javascript写的日历类(基于pj)”的完整攻略。 说明 这是一篇关于使用PJ写的Javascript日历类的攻略,PJ是一种Javascript的类库,它能简化Javascript日历类的编写过程,也更加易于管理、维护日历类。在这篇攻略中,我将介绍如何使用PJ来编写日历类,包括其基本用法和关键代码。以下是两个简单的示例,分别展示了日历类的基本…

    JavaScript 2023年5月27日
    00
  • 详解JavaScript实现异步Ajax

    详解JavaScript实现异步Ajax Ajax(Asynchronous JavaScript and XML)即异步JavaScript和XML,是指页面无需刷新就能与服务器交换数据的技术。使用Ajax可以使网页更加高效,有良好的用户体验。在JavaScript中,可以使用XMLHttpRequest对象实现AJAX异步请求和响应。下面是如何实现Aja…

    JavaScript 2023年6月10日
    00
  • JavaScript中的console.time()函数详细介绍

    下面是关于JavaScript中的console.time()函数的详细介绍: 简介 console.time()函数可以帮助我们计算代码的执行时间。通常用于优化代码,或者进行一些性能测试等等。 语法 console.time()函数的语法如下: console.time(name); 参数name是一个字符串,用于标记计时器。 使用方法 使用console…

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