一、技術概述
做什么:基於SpringBoot使用Email進行驗證碼校驗方法;原因:有關注冊、忘記密碼功能需要一定的驗證來保證賬號的安全性;難點:分為兩部分,一部分就是如何發送email郵件,另一部分就是如何校驗驗證碼,下面也將從這兩個難點出發進行闡述。
二、技術詳述
首先介紹以下如何發送email郵件:
1)准備工作
- 需要開啟POP3、SMTP郵件服務
- 需要設置客戶端授權碼
- 以網易郵箱舉例如下:


2)、發送郵件模板
i、添加依賴
在Spring Boot的工程中的 pom.xml 中引入 spring-boot-starter-mail 依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
ii、綁定配置
application.yml
spring:
mail:
host: smtp.163.com
username: xxxxxx@163.com
password: xxxxxxxxxxxxxx
properties:
mail:
smtp:
starttls:
enable: true
required: true
注意:在spring.mail.password處的值是需要在郵箱設置里面生成的授權碼,這個不是真實的密碼。
iii、測試發送
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTests {
@Autowired
private JavaMailSender mailSender;
@Test
public void sendSimpleMail() throws Exception {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("dyc87112@qq.com"); //設置郵件發送者
message.setTo("10001@qq.com"); //設置郵件接收者
message.setSubject("主題:簡單郵件"); //設置郵件主題
message.setText("測試郵件內容"); //設置郵件內容
mailSender.send(message);
}
}
引入了 spring-boot-starter-mail 依賴之后,會根據配置文件中的內容去創建 JavaMailSender 實例,因此我們可以直接在需要使用的地方直接 @Autowired 來引入郵件發送對象。
到此,一個簡單的郵件發送就完成,也就說我們已經能夠將生成的隨機驗證碼發送到用戶郵箱,那么如何根據生成的驗證碼進行校驗呢?也就是上面提到的難點的另一部分:
思路也很簡單:就是將隨機生成的驗證碼correctCode加密后的密文hash和時間tamp放入map中一並返回給前端,校驗時,前端再傳回的map和用戶輸入的驗證碼inputCode,再將inputCode進行同樣的加密與傳回的map中的hash進行對比,相同則驗證碼輸入正確,否則輸入錯誤,如此也能設置tamp保證一定的時效性。
上代碼:
private static final String KEY = "XXXX"; // KEY為自定義秘鑰
原文采用依賴Google的guava包中的MD5加密,我比較懶,不想導入依賴,直接用Spring框架中繼承的DigestUtils工具類進行加密。
加密:
String code = VerifyCode(6); //隨機數生成6位驗證碼
sendEmail(code); //發送驗證碼
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 5);
String currentTime = sf.format(c.getTime());// 生成5分鍾后時間,用戶校驗是否過期
String hash = DigestUtils.md5DigestAsHex((KEY + "@" + currentTime + "@" + code).getBytes());//生成MD5值
Map<String, Object> resultMap = new HashMap<>(); //返回的map
resultMap.put("hash", hash);
resultMap.put("tamp", currentTime);
return resultMap;
校驗:
public String VerifyCode(@RequestBody Map<String,Object> requestMap, @PathVariable("verification") String code){
String requestHash = requestMap.get("hash").toString();
String tamp = requestMap.get("tamp").toString();
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");//當前時間
Calendar c = Calendar.getInstance();
String currentTime = sf.format(c.getTime());
if (tamp.compareTo(currentTime) > 0) {
String hash = DigestUtils.md5DigestAsHex((KEY + "@" + tamp + "@" + code).getBytes());//生成MD5值
if (hash.equalsIgnoreCase(requestHash)){
//校驗成功
return "success";
}else {
//驗證碼不正確,校驗失敗
return "failed";
}
} else {
// 超時
return "failed";
}
}
到此,就完成驗證碼校驗而不必每次都存儲新生成的驗證碼等待驗證而浪費存儲空間。安全性與采用的加解密算法相關,應該也相對安全。
三、技術使用中遇到的問題和解決過程。
困難:除了上述兩個難點(主要問題)的解決以外(在參考了別人的思路之后,可以說已經沒什么大問題了),只剩其中一些瑣碎的小問題,比如驗證碼如何生成:
由於對驗證碼要求不高,所以就直接采用生成n位數字(更復雜的可以是字母數字組合,或者與圖形結合)驗證碼生成比較簡單,只是通過隨機數生成n位數字,采用隨機數即可解決。
生成驗證碼:
private String VerifyCode(int n){
Random r = new Random();
StringBuffer sb =new StringBuffer();
for(int i = 0;i < n;i ++){
int ran1 = r.nextInt(10);
sb.append(String.valueOf(ran1));
}
// System.out.println(sb);
return sb.toString();
}
還有一個小問題便是如何對生成驗證碼進行加密,這里在查閱資料后了解到Springboot已經封裝了相應的工具類,不用白不用嘛,即如下DigestUtils 的 md5加密方法,這里我往里添加了KEY我們的默認密鑰,currenttime用來保證驗證碼的時效性,上面代碼已經提到,這里不再贅述。
String hash = DigestUtils.md5DigestAsHex((KEY + "@" + currentTime + "@" + code).getBytes());//生成MD5值
值得一提的是,還有一點,就是上述配置在部署時可能出錯,因為如果不設置端口的話,email默認端口port將會是25,而在阿里雲服務器上25 port好像是被禁用的,因此我們最好改一下端口配置,否則在部署到雲端時發送email功能不能正常運行,配置如下:
spring:
mail:
host: smtp.163.com
username: a_shadouyou@163.com
password: OKQXJTQRTZGZACRK
properties:
mail:
smtp:
starttls:
enable: true
required: true
socketFactory:
class: javax.net.ssl.SSLSocketFactory
port: 465 #改端口為465,雲端服務器只需開啟465端口即可
到此,已經解決了當初的需求,完成了郵箱驗證的功能。
四、總結。
上面比較繁雜,說了大多是細節,這里進行一些簡略的小結:
完成郵箱驗證需要由兩部分:生成驗證碼發送到用戶郵箱 - -> 對用戶的輸入驗證碼進行校驗。
發送郵件簡單,通過設置郵箱后,直接導入依賴,完成相應配置(這里是application.yml ,properties也可),然后編寫相應業務邏輯即可;
校驗驗證碼比較復雜,但思路也很簡單,就是將隨機生成的驗證碼加密后的密文返回給前端,校驗時,前端再傳回的map和用戶根據郵箱提示輸入的驗證碼,前端頁面再將輸入驗證碼與一開始收到的密文傳回,后端進行校驗,相同則驗證碼輸入正確,否則輸入錯誤。
說白了,就是這么簡單,這都歸功於Spring Boot 封裝的工具類以及結合的依賴給我們的開發帶來了極大的便利啊!
五、參考
參考如下:
SpringBoot發送注冊激活郵件(附HTML模板)(作者:不愛編程的設計師)
SpringBoot配置Email發送功能(作者:牧野流冰87)
SpringBoot實現短信驗證碼校驗(作者:一只因特馬)
注:以上參考可能不是來自第一手作者。
