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.
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.
After clicking the link you will see
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.