用户邮箱(REST)验证(Spring Boot)

要在Spring Boot的登录注册流程中添加邮箱验证,通常步骤如下:

  1. 用户注册时发送验证码邮件: 在用户注册时,你可以生成一个验证码(或一个验证链接),并将其通过邮件发送给用户。
  2. 用户点击邮件中的验证链接: 用户收到邮件并点击验证链接后,后台会检查验证码是否有效,如果有效,就将用户的状态标记为已验证。
  3. 邮箱验证后的登录: 只有邮箱验证通过的用户才能登录。

步骤 1:添加依赖

首先,确保你的项目中已经引入了 Spring Boot 的邮件库。在 build.gradle 文件中添加以下依赖:

dependencies {
        implementation 'javax.mail:javax.mail-api:1.6.2'
        implementation 'org.springframework.boot:spring-boot-starter-mail'
}

步骤 2:添加邮件发送功能

接下来,需要配置邮件发送功能。你可以使用 Spring Boot 的 JavaMailSender 来发送邮件。

  1. 在 application.properties 中配置邮件服务器(这里我使用的是qq邮箱服务器,可以根据自己的需要配置其它的邮箱服务器):
spring.mail.host=smtp.qq.com
spring.mail.port=587
spring.mail.username=xx@qq.com//邮箱账号
spring.mail.password=xxxx//邮箱密码|授权码
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
  1. 创建一个邮件发送服务:
package com.example.demo.service;

import jakarta.mail.internet.MimeMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.MailException;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;

@Service
public class EmailService {
    private final JavaMailSender mailSender;

    public EmailService(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void sendVerificationEmail(String to, String token) throws MailException, MessagingException, jakarta.mail.MessagingException {
        String subject = "Please verify your email address";
        String text = "Click the following link to verify your email: " +
                "http://localhost:8080/verify?token=" + token;

        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom("xx@qq.com");
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(text);

        mailSender.send(message);
    }
}

步骤 3:更新实体类以支持邮箱功能

为其添加带参构造函数以及email verificationToken verified字段:

package com.example.demo.model;

import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Size;

@Entity
@Table(name = "users")
public class User {
    // 无参构造函数
    public User() {}

    // 带参构造函数
    public User(String email, String password, String verificationToken, boolean verified) {
        this.email = email;
        this.password = password;
        this.verificationToken = verificationToken;
        this.verified = verified;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    @Size(min=2, max=20, message = "username must be at least 2 characters long and at most 20 characters")
    private String username;

    @Column(nullable = false)
    @Size(min=2, max=20, message = "password must be at least 2 characters long and at most 20 characters")
    private String password;

    @Column(nullable = false, unique = true)
    @Email(message = "Wrong email format")
    private String email;

    private String verificationToken;

    private boolean verified;

    getter and setter...

步骤 4:生成Token并保存

更改用户登陆注册服务UserService以生成Token并将其存储在数据库中,确保它有一定的有效期。

package com.example.demo.service;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.UUID;

@Service
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final EmailService emailService;

    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, EmailService emailService) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.emailService = emailService;
    }

    public void registerUser(String email, String username, String password) {
        if (userRepository.findByUsername(username).isPresent()) {
            throw new RuntimeException("Username is already taken.");
        }
        if (userRepository.findByEmail(email).isPresent()) {
            throw new RuntimeException("Email is already taken.");
        }
        // 1. 创建用户实体,存储到数据库
        String token = UUID.randomUUID().toString();
        User user = new User(email, username, passwordEncoder.encode(password), token, false); // false 表示未验证
        userRepository.save(user);

        // 2. 发送验证邮件
        try {
            emailService.sendVerificationEmail(email, token);
        } catch (Exception e) {
            // 处理邮件发送失败的情况
            e.printStackTrace();
        }
    }

    public Boolean loginUser(String username, String password) {
        ...
    }
}

步骤 5:更新UserRepository

为其增加findByVerificationToken()方法

package com.example.demo.repository;

import com.example.demo.model.User;
import org.springframework.data.repository.CrudRepository;

//@Repository
public interface UserRepository extends CrudRepository<User, Long> {
    ...
    User findByVerificationToken(String username);
}

步骤 6:验证邮件链接

在收到用户点击验证链接后,后台根据URL中的token查找用户并更新其状态。

package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.stereotype.Controller;

@Controller
public class VerificationController {
    private final UserRepository userRepository;

    public VerificationController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping("/verify")
    public String verifyEmail(@RequestParam("token") String token) {
        User user = userRepository.findByVerificationToken(token);
        if (user != null && !user.isVerified()) {
            user.setVerified(true);
            user.setVerificationToken(null); // 清除 token
            userRepository.save(user);
            return "redirect:/login"; // 返回验证成功的页面
        } else {
            return "redirect:/error"; // 验证失败或已验证的情况
        }
    }
}

步骤 7:用户登录时检查邮箱验证状态

在用户登录时,检查用户是否已经验证邮箱,如果没有验证则拒绝登录。

package com.example.demo.service;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.stereotype.Service;
import java.util.Optional;
import ...

@Service
public class UserService {
    private final UserRepository userRepository;
    ...

    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, EmailService emailService) {
        this.userRepository = userRepository;
        ...
    }

    public void registerUser(String email, String username, String password) {
        ...
    }

    public Boolean loginUser(String username, String password) {
        Optional<User> user = userRepository.findByUsername(username);
        if (user.isPresent() && passwordEncoder.matches(password, user.get().getPassword()) && user.get().isVerified()) {
            return true;
        };
        return false;
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容