今天我们来看看如何用 Spring Boot 简易搭建一个邮箱验证接口。
许多的网站在注册账号之后,都会发送一封邮件到注册邮箱里,而用户需要到邮箱里打开这封验证邮件,并点击邮件里的链接,以向网站证明自己为该邮箱的拥有者。
1. 配置邮箱参数
为了让 Spring Boot 在用户注册成功的时候发送邮件,我们需要先添加一个邮箱服务依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
1
2
3
4
我们需要配置一个邮箱服务来帮我们发送验证邮箱的邮件,但在配置邮箱参数之前,我们要先决定使用哪一个邮箱服务。这里我们以 QQ 邮箱为例子,朋友们也可以搭建自己的邮箱服务器。
登录 QQ 邮箱之后,点击 设置 -> 账户,打开 “POP3/SMTP服务”,接着取得第三方客户端授权码。
接着我们打开 application.properties 文件来进行配置:
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
1
2
3
4
5
6
7
8
2. 创建实体类
当用户完成注册之后,我们需要在邮箱验证表里创建一条记录使用户的邮箱与一个的加密 token 匹配,以提升之后验证邮箱时的安全性。
用户需要点击带有该 token 参数的网址,接着我们会检查这个表,token 核对成功之后才算是成功验证邮箱。
创建一个邮箱验证表实体类:
@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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
接着创建一个用户实体类。我们需要给用户实体类一个 boolean 值的属性,代表其邮箱是否已经通过验证。默认为 false,因为刚注册成功的时候邮箱肯定是还没有通过验证的。
@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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3. 创建仓库类
我们需要写一个简单的用户仓库类
@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();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
接着再写一个简单的邮箱仓库类
@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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
4. 创建服务类
由于当我们向 QQ 邮箱发送请求时,整个线程需要等待 QQ 邮箱服务器返回发送结果,因此会导致线程堵塞,所以我们可以使用多线程来对 QQ 邮箱发送异步请求。
首先我们需要创建一个线程池配置类:
@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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
接着在我们的邮箱业务逻辑中,我们会需要使用到 @Async 注解。
编写一个邮箱服务类
@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("xxxx@qq.com"); // 填写你的 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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
这里我们使用 JWT 来作为我们的 token,因此我们需要添加 JWT 依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
1
2
3
4
5
然后我们写一个用户的服务类
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
5. 编写 REST 接口
我们还需要写 REST 接口来处理用户注册与验证邮箱的请求。
@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();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
大功告成!让我们来测测实际效果。
实际效果
首先通过注册 REST API 注册一个账户。
可以使用 Postman 发送注册请求:
// 你的主机地址/api/v1/user/signup
{
"email": "填写你的邮箱",
"password": "123123"
}
1
2
3
4
5
接着就会收到一封邮箱验证邮件。
点击链接之后就会看到
接着我们到 Users 表查看用户的邮箱验证情况,已经从 false 变为 true了。
至此,一个简单的邮箱验证系统就搭建完了。
————————————————
版权声明:本文为CSDN博主「David Chou」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/vandavidchou/article/details/103514049