其他方案=>引入短信服務發(fā)送手機驗證碼進行安全校驗
操作相對復雜且收費,詳細教程可供參考選擇
在我們進行登錄注冊等等敏感操作時,為了保證用戶信息的安全性,常常會碰到需要接收手機短信驗證碼進行驗證的場景,雖然它的安全系數相對較高,但是引入手機驗證碼使用需要進行付費,顯然不適合我們個人項目的學習,于是我們可以嘗試使用各大平臺的提供的郵件服務進行安全校驗,步驟基本一致,本處我們采用QQ郵箱進行演示。
一.需求分析
-
場景:用戶輸入自己的郵箱,點擊獲取驗證碼,后臺會發(fā)送一封郵件到對應郵箱中。
-
分析:防止刷爆郵箱,可以限制一分鐘內只能獲取一次。
- 前端:期限內禁用button按鈕。
- 后端:存入redis設置過期時間,請求先判斷redis中是否有數據。
二.環(huán)境準備
(1) 郵箱環(huán)境
在QQ郵箱中開啟SMTP服務,獲取授權碼(主要步驟,后端操作各平臺郵箱基本一致)
-
網頁版:進入郵箱,點擊設置中的賬戶
-
往下翻可以看到如下服務開關,點擊開啟
點擊開啟后會得到一串授權碼,后端程序中需要用到。
- 可能會要求完成相關安全驗證
(2) 后端環(huán)境
大概率是在web項目中使用到,因此我們創(chuàng)建一個SpringBoot工程
- 創(chuàng)建好項目后在pom文件中導入操作郵箱所需jar包
<!--QQ郵箱驗證碼所需jar包-->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
</dependency>
- 由于我們需要在spring項目使用redis緩存驗證碼,在一定程度上保障接口安全性,因此還要導入redis的jar包
<!-- 使用redis緩存驗證碼時效-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 在yml文件中配置redis,設置了redis密碼需要加上密碼配置,否則可以不加
spring:
redis:
# redis數據庫索引(默認為0),我們使用索引為3的數據庫,避免和其他數據庫沖突
database: 3
# redis服務器地址(默認為localhost)
host: localhost
# redis端口(默認為6379)
port: 6379
三.后端程序
(1) 效果實現
- 發(fā)送郵箱應該算個工具,因此我們可以在工具類中寫入如下代碼
package com.example.utils;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
public class SendMailUtil {
/**
* 發(fā)送郵件代碼
*
* @param targetEmail 目標用戶郵箱
* @param authCode 發(fā)送的驗證碼
*/
public static void sendEmailCode(String targetEmail, String authCode) {
try {
// 創(chuàng)建郵箱對象
SimpleEmail mail = new SimpleEmail();
// 設置發(fā)送郵件的服務器
mail.setHostName("smtp.qq.com");
// "你的郵箱號"+ "上文開啟SMTP獲得的授權碼"
mail.setAuthentication("158xxx69@qq.com", "fbsxxxxxsijdj");
// 發(fā)送郵件 "你的郵箱號"+"發(fā)送時用的昵稱"
mail.setFrom("15xxx69@qq.com", "觀止");
// 使用安全鏈接
mail.setSSLOnConnect(true);
// 接收用戶的郵箱
mail.addTo(targetEmail);
// 郵件的主題(標題)
mail.setSubject("注冊驗證碼");
// 郵件的內容
mail.setMsg("您的驗證碼為:" + authCode+"(一分鐘內有效)");
// 發(fā)送
mail.send();
} catch (EmailException e) {
e.printStackTrace();
}
}
}
- 編寫如下接口
@RestController
public class SendMail {
@PostMapping("/getCode")
@ResponseBody
public String mail(@RequestParam("targetEmail") String targetEmail) {
// 隨機生成六位數驗證碼
String authCode = String.valueOf(new Random().nextInt(899999) + 100000);
SendMailUtil.sendEmailCode(targetEmail,authCode);
return "ok";
}
}
- 讓我們測試一下接口
GET http://localhost:8080/getCode?targetEmail=35xxxx947@qq.com
可以看到如下效果:
如此我們初步效果就已經實現啦~
(3) 緩存改進
上述程序我們瘋狂發(fā)送請求可以一直發(fā)送郵箱,這顯然不是我們所期待的,接下來我們加入redis來改進一下。
@RestController
public class SendMail {
@Resource
private RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
/**
* @param targetEmail 用戶郵箱
* @return
*/
@GetMapping("/getCode")
@ResponseBody
public String mail(@RequestParam("targetEmail") String targetEmail) {
// 發(fā)送前先看下我們是否已經緩存了驗證碼
String yzm = redisTemplate.opsForValue().get("yzm");
// 判斷是否存在
if (yzm == null){
// 生成六位數驗證碼
int authNum = new Random().nextInt(899999) + 100000;
String authCode = String.valueOf(authNum);
// 不存在,我們發(fā)送郵箱給用戶
SendMailUtil.sendEmailCode(targetEmail, "你的驗證碼為:" + authCode + "(五分鐘內有效)");
// 存入redis中,設置有效期為1分鐘
redisTemplate.opsForValue().set("yzm", authCode, 1, TimeUnit.MINUTES);
return "發(fā)送成功";
}
// 存在,直接返回,不再發(fā)送郵箱~
return "請勿重復發(fā)送驗證碼";
}
}
如此再次測試,可以發(fā)現瘋狂點擊不再產生效果,成功被攔截,如此安全了許多
至此我們開始想要的效果便已經在小demo中實現了,接下來可以引入正式自己項目啦
四.線上部署問題
按上述代碼本地運行正常,但部署到線上環(huán)境如果產生如下錯誤:
1.Sending the email to the following server failed : smtp.163.com:465
2.Could not connect to SMTP host: smtp.163.com, port: 465
3.No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
原因:阿里云等服務器廠商禁用了默認的25端口,我們需要使用例如465等可用端口發(fā)送郵件并開啟ssl連接,并進行如下相關配置即可,最后在服務器防火墻開放對應窗口即可。
/**
* 驗證獲取操作安全證書
*/
public class CheckCodeUtils {
/**
* 發(fā)送郵件代碼
*
* @param targetEmail 目標用戶郵箱
* @param authCode 發(fā)送的驗證碼
*/
public static String GetEmailCode(String targetEmail, String authCode) {
try {
// 創(chuàng)建郵箱對象
SimpleEmail mail = new SimpleEmail();
// 設置發(fā)送郵件的服務器
mail.setHostName("smtp.qq.com");
// "你的郵箱號"+ "上文開啟SMTP獲得的授權碼"
mail.setAuthentication("fsp1xxxx@qq.com", "GHNUxxxxxVL");
// 發(fā)送郵件 "你的郵箱號"+"發(fā)送時用的昵稱"
mail.setFrom("fsp15xxx@qq.com", "伙伴匹配系統(tǒng)");
// 發(fā)送服務端口
mail.setSslSmtpPort(String.valueOf(465));
// 使用安全鏈接
mail.setSSLOnConnect(true);
System.setProperty("mail.smtp.ssl.enable", "true");
System.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");
// 接收用戶的郵箱
mail.addTo(targetEmail);
// 郵件的主題(標題)
mail.setSubject("注冊驗證碼");
// 郵件的內容
mail.setMsg("【伙伴匹配系統(tǒng)】您的驗證碼為:" + authCode + "(5分鐘內有效)");
// 發(fā)送
mail.send();
return "發(fā)送成功,請注意查收";
} catch (EmailException e) {
return e.getMessage();
}
}
}
五.前端(補充)
用原生js簡單寫了一個界面,感興趣的可以看一看文章來源:http://www.zghlxwxcb.cn/news/detail-439908.html
代碼如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-439908.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<input id="mail" type="text">
<button id="getCode">獲取驗證碼</button>
</div>
<script>
/*按鈕禁用60秒,并顯示倒計時*/
function disabledButton() {
const getCode = document.querySelector("#getCode")
getCode.disabled = true
let second = 60;
const intervalObj = setInterval(function () {
getCode.innerText = "請" + second + "秒后再重試"
if (second === 0) {
getCode.innerText = "獲取驗證碼"
getCode.disabled = false
clearInterval(intervalObj);
}
second--;
}, 1000);
}
document.querySelector("#getCode").addEventListener('click', function () {
const mail = document.querySelector("#mail")
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:8080/getCode?targetEmail=" + mail.value, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
alert(xhr.response);
disabledButton()
}
}
})
</script>
</body>
</html>
到了這里,關于引入QQ郵箱發(fā)送驗證碼進行安全校驗的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!