Step 5 Spring Boot up makeshift mail verification system to their own projects plus 35 points

Today we look at how to build a simple Spring Boot-mail verification interface.

Many website after registering an account, a message will be sent to registered mailbox, and the user needs to open the e-mail in the verification email and click the link in the email to prove that the owner of their own mailbox to the site.

1. Configure mailbox parameters

To make Spring Boot send a message when the user registration is successful, we need to add a mail service dependency.

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

We need to configure a mail service to help us send a verification message mailbox, but before the mailbox configuration parameters, we must first determine which mailbox service. Here we QQ mailbox for example, friends can also build their own mail server.

After you log QQ mailbox, click Settings -> Accounts, open the "POP3 / SMTP service", followed by a third-party client to obtain an authorization code.
Here Insert Picture Description
Then we open application.properties file to configure:

spring.mail.host=smtp.qq.com
spring.mail.protocol=smtp
spring.mail.username= # 填写你的发件邮箱地址
spring.mail.password= # 填写第三方客户端授权码
spring.mail.default-encoding=UTF-8
spring.mail.port=465
# 此为邮件加密服务
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
2. Create entity classes

When the user registration is completed, we need to create a record of the user's mailbox with a unique encrypted token verification table match in the mailbox, the mailbox security when verifying after to improve.

Users need to click on the token with URL parameters, then we will check the table, after the success of a truly successful token check to verify the mailbox.

Create a mailbox table validation entity classes:

@Entity
@Table(name = "email_verifier")
public class EmailVerifier {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String email;

    private int userId;

	// 验证用的 token
    private String token;

	// getters and setters
}

Then create a user entity class. We need to give the user entity attribute boolean value of a class, does it mean that their mailboxes have been authenticated. The default is false, because just when successfully registered the mailbox is certainly not yet validated.

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

    private String email;

	// 邮箱是否成功验证,默认为 false
    @Column(name = "is_email_verified", columnDefinition = "boolean default false")
    private boolean isEmailVerified;

    @JsonIgnore
    private String password;

	// getters and setters
}
3. Create a warehouse class

We need to write a simple user class warehouse

@Repository
@Transactional
public class UserRepositoryImpl implements UserRepository {
    @PersistenceContext
    private EntityManager entityManager;

	// 将新用户插入用户表
    public void addUser(String email, String password) {
 		User user = new User();
 		entityManager.persist(user);
 		user.setEmail(email);
 		user.setPassword(password);
        entityManager.flush();
    }

	// 将用户表里的邮箱是否已验证属性设为 true
    public void setUserEmailVerified(int userId) {
        User user = findById(userId);
        entityManager.persist(user);
        user.setEmailVerified(true);
        entityManager.flush();
    }
}

Then write a simple email warehouse class

@Repository
@Transactional
public class EmailRepositoryImpl implements EmailRepository {
    @PersistenceContext
    private EntityManager entityManager;
    
    // 往邮箱验证表添加新注册用户邮箱
    public void addEmailVerifier(int userId, String email, String token) {
        EmailVerifier emailVerifier = new EmailVerifier();
        entityManager.persist(emailVerifier);
        emailVerifier.setUserId(userId);
        emailVerifier.setEmail(email);
        emailVerifier.setToken(token);
        entityManager.flush();
    }

	// 根据用户 id 取得邮箱验证表数据
    public EmailVerifier getEmailVerifierByUserId(int userId) {
        EmailVerifier emailVerifier = entityManager.createQuery("SELECT e FROM EmailVerifier e WHERE e.userId = :userId", EmailVerifier.class)
                                        .setParameter("userId", userId)
                                        .getSingleResult();
        return emailVerifier;
    }

	// 根据 token 取得邮箱验证表数据
    public EmailVerifier getEmailVerifierByToken(String token) {
        EmailVerifier emailVerifier = entityManager.createQuery("SELECT e FROM EmailVerifier e WHERE e.token = :token", EmailVerifier.class)
                                        .setParameter("token", token)
                                        .getSingleResult();
        return emailVerifier;
    }
}
4. Create a service class

Because when we send a request to the QQ mailbox, the whole thread needs to wait for QQ-mail server sends back the results, and therefore causes the thread blocked , so we can multithreading to send an asynchronous request to use QQ mailbox .

First we need to create a thread pool configuration class:

@EnableAsync // 使用该注解,这样 Spring Boot 才会扫描 @Async 注解
@Configuration
public class TaskPoolConfig {
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(8);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("task-executor");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(600);
        return executor;
    }
}

Then the business logic in our mailbox, we will need to use @Async comment.

Write a mail service class

@Service
public class EmailServiceImpl implements EmailService {
    
    @Autowired
    private MailSender mailSender;

    @Autowired
    private EmailRepository emailRepository;

    @Autowired
    private UserRepository userRepository;

    @Async("taskExecutor")
    @Override
    public void sendVerificationEmail(int userId) {
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            EmailVerifier emailVerifier = getEmailVerifierByUserId(userId);
            String email = emailVerifier.getEmail();
            String token = emailVerifier.getToken();
            String text = "请点击链接验证邮箱: https://此处输入你的主服务器地址/api/v1/user/email_verification?token=" + token; 
            simpleMailMessage.setTo(email);
            simpleMailMessage.setSubject("Email Verification");
            simpleMailMessage.setFrom("[email protected]"); // 填写你的 QQ 邮箱地址
            simpleMailMessage.setText(text);
            mailSender.send(simpleMailMessage);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public void addEmailVerifier(int userId, String email, String token) {
        emailRepository.addEmailVerifier(userId, email, token);
    }

    public EmailVerifier getEmailVerifierByUserId(int userId) {
        return emailRepository.getEmailVerifierByUserId(userId);
    }

    public EmailVerifier getEmailVerifierByToken(String token) {
        EmailVerifier emailVerifier = emailRepository.getEmailVerifierByToken(token);
        return emailVerifier;
    }

    public void setUserEmailVerified(int userId) {
        userRepository.setUserEmailVerified(userId);
    }
}

Here we use JWT as our token, we need to add JWT rely

<dependency>
	<groupId>com.auth0</groupId>
	<artifactId>java-jwt</artifactId>
	<version>3.4.0</version>
</dependency>

Then we wrote a user of the service class

public class UserServiceImpl implements UserService {

	@Autowired
	private UserRepository userRepository;

	@Autowired
	private EmailService emailService;
	
	// 这是生成 token 的密钥
	private String tokenSecret = "my-secret-string";

	// 添加新用户
	public void addUser(String email, String password) {
		User user = userRepository.addUser(email, password);
		int userId = user.getId();
		String token = token = JWT.create().sign(Algorithm.HMAC256(tokenSecret));
		emailService.addEmailVerifier(userId, email, token);
		emailService.sendVerificationEmail(userId);
	}
}
5. Write a REST interface

We need to write REST interface to handle user registration and verify the email request.

@CrossOrigin
@RestController
@RequestMapping(value = "/api/v1/user")
public class UserController {

    @Autowired
    private EmailService emailService;

	@Autowired
	private UserService userService;

	// 用户注册 REST 接口
    @PostMapping(value = "/signup")
    public ResponseEntity<Object> signUp(@RequestBody Map<String, String> payload) {
        JSONObject result = new JSONObject();
        String email = payload.get("email");
        String password = payload.get("password");
        JSONObject addUserResult = userService.addUser(email, password);
		return ResponseEntity.ok().build();
    } 

	// 用户验证邮箱 REST 接口
    @GetMapping(value = "/email_verification")
    public ResponseEntity<Object> verifyEmail(HttpServletRequest request) {
        String token = request.getParameter("token");
        EmailVerifier emailVerifier = emailService.getEmailVerifierByToken(token);
        if (emailVerifier != null) {
            int userId = emailVerifier.getUserId();
            emailService.setUserEmailVerified(userId);
            return ResponseEntity.ok().body("邮箱验证成功");
        } else {
            return ResponseEntity.badRequest().build();
        }
    }
}

We're done! Let Cece practical effect.

actual effect

First, sign up for an account by registering REST API.

You may send a registration request to use Postman:

// 你的主机地址/api/v1/user/signup
{
	"email": "填写你的邮箱",
	"password": "123123"
}

Then you will receive an email verification message.

Here Insert Picture Description

After clicking the link you will see

Here Insert Picture Description

Then we see the Users table to verify the user's mailbox has become true from the false.

Thus, a simple email verification system to build finished.

Published 14 original articles · won praise 8 · views 2200

Guess you like

Origin blog.csdn.net/vandavidchou/article/details/103514049
Recommended