SpringBoot實現(xiàn)短信發(fā)送及手機驗證碼登錄
一、短信發(fā)送
1.1 阿里云短信服務(wù)
短信服務(wù)_企業(yè)短信營銷推廣_驗證碼通知-阿里云
也可以在下面這個地方查看短信服務(wù)

1.1.1 設(shè)置短信簽名
短信簽名就是短信發(fā)送者的署名,表示發(fā)送方的身份
1.1.2 模板管理

申請下來之后可以點擊詳情進行查看
其中模板CODE是自動生成的,不用管,重點是模板的內(nèi)容

1.1.3 設(shè)置AccessKey


創(chuàng)建新的用戶

勾選上之后,我們在編程代碼中就能使用

當我們創(chuàng)建用戶成功后,就生成了一對AccessKey,即AccessKey ID(用戶名) 與AccessKey Secret(密碼)
很多人在這里的時候不小心沒截圖或者沒保存就關(guān)了,丟失了AccessKey,但是不要緊,還可以再次創(chuàng)建
還有就是如果別人知道了我們的AccessKey,那別人使用的時候會就花我們的錢。我們也可以把泄露的AccessKey禁用

之后再新增授權(quán)。這次授權(quán)的意思就是僅僅授予有關(guān)短信服務(wù)的,即是我們泄露了,別人也只能操作短信服務(wù),對我們的影響很小。

1.2 短信發(fā)送——代碼開發(fā)
參照官方文檔即可
1.2.1 導(dǎo)入maven坐標
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>2.1.0</version>
</dependency>1.2.2 調(diào)用API
/**
* 短信發(fā)送工具類
*/
public class SMSUtils {
/**
* 發(fā)送短信
* @param signName 簽名
* @param templateCode 模板
* @param phoneNumbers 手機號
* @param param 參數(shù)
*/
public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tHRxs2FeCu5JcJTGbm2", "v0H4PaJpXSwNr6XChtlVYAgmQWgKRA");
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setSysRegionId("cn-hangzhou");
// 要發(fā)送給那個人的電話號碼
request.setPhoneNumbers(phoneNumbers);
// 我們在阿里云設(shè)置的簽名
request.setSignName(signName);
// 我們在阿里云設(shè)置的模板
request.setTemplateCode(templateCode);
// 在設(shè)置模板的時候有一個占位符
request.setTemplateParam("{\"code\":\""+param+"\"}");
// request.setPhoneNumbers("1368846****");//接收短信的手機號碼
// request.setSignName("阿里云");//短信簽名名稱
// request.setTemplateCode("SMS_20933****");//短信模板CODE
// request.setTemplateParam("張三");//短信模板變量對應(yīng)的實際值
try {
SendSmsResponse response = client.getAcsResponse(request);
System.out.println("短信發(fā)送成功");
}catch (ClientException e) {
e.printStackTrace();
}
}
}1.3 手機驗證碼登錄
- 方便、快捷、無需注冊、直接登陸
- 使用短信驗證碼作為登錄憑證,無序記憶密碼
- 安全
登錄流程: 輸入手機號 -> 獲取驗證碼 -> 輸入驗證碼 -> 點擊登錄 -> 登陸成功
注意: 通過手機驗證碼登錄,手機號是區(qū)分不同用戶的標識
1.3.1 用戶數(shù)據(jù)庫表
因為是通過手機和驗證碼登錄的,所以沒有用戶名和密碼字段

1.3.2 修改過濾器
在寫代碼之前記得要在過濾器中定義不需要處理的請求路徑/user/sendMsg和/user/login
然后訪問路徑: http://localhost:8080/front/page/login.html
/**
* 檢查用戶是否已經(jīng)完成登錄
* 過濾器與攔截器的區(qū)別:Filter對所有訪問進行增強(在Tomcat服務(wù)器進行配置),Interceptor僅針對SpringMVC的訪問進行增強
*/
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*") //urlPatterns指定攔截哪些路徑
public class LoginCheckFilter implements Filter {
// 此對象的作用:路徑匹配器, 匹配路徑時支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// servletRequest向下強制類型轉(zhuǎn)換
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1. 獲取本次請求的URI( URI:請求的資源路徑)
String requestURI = request.getRequestURI();
log.info("攔截到請求:{}", request.getRequestURI());
// 定義不用處理的請求路徑
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**",
"/common/**",
"/user/sendMsg",
"/user/login"
};
//2. 判斷本次請求是否需要處理(因為有些請求并不需要用戶登錄)
boolean check = check(requestURI, urls);
//3.如果不需要處理,則直接放行
if (check) {
log.info("本次請求{}不需要處理", request.getRequestURI());
filterChain.doFilter(request, response);
return;
}
//4-1.判斷登錄狀態(tài),如果已登錄,則直接放行.從session中獲取用戶,如果獲取到說明已經(jīng)登錄
if (request.getSession().getAttribute("employee") != null) {
log.info("用戶已登錄,用戶id為{}", request.getSession().getAttribute("employee"));
Long empId = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
filterChain.doFilter(request, response);
return;
}
//4-2.判斷登錄狀態(tài),如果已登錄,則直接放行.從session中獲取用戶,如果獲取到說明已經(jīng)登錄
if (request.getSession().getAttribute("user") != null) {
log.info("用戶已登錄,用戶id為{}", request.getSession().getAttribute("user"));
Long userId = (Long) request.getSession().getAttribute("user");
BaseContext.setCurrentId(userId);
filterChain.doFilter(request, response);
return;
}
//5.如果未登錄則返回未登錄結(jié)果
log.info("資源路徑路徑:{},用戶未登錄{}", request.getRequestURI(), request.getSession().getAttribute("employee"));
// 通過輸出流的方式向客戶端響應(yīng)數(shù)據(jù) (為什么要返回這個NOTLOGIN? 因為前端需要這個來進行判定是否登錄)
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
// filterChain.doFilter(request, response); 加上這個就無法實現(xiàn)
}
/**
* 檢查本次請求是否需要放行
*
* @param requestURI 請求的資源路徑
* @param urls 放過的路徑
* @return true 放行
*/
public boolean check(String requestURI, String[] urls) {
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if (match) {
// 放行
return true;
}
}
return false;
}
}1.3.3 隨機生成驗證碼的工具類
/**
* 隨機生成驗證碼工具類
*/
public class ValidateCodeUtils {
/**
* 隨機生成驗證碼
* @param length 長度為4位或者6位
* @return
*/
public static Integer generateValidateCode(int length){
Integer code =null;
// 長度為4
if(length == 4){
code = new Random().nextInt(9999);//生成隨機數(shù),最大為9999
if(code < 1000){
code = code + 1000;//保證隨機數(shù)為4位數(shù)字
}
// 長度為6
}else if(length == 6){
code = new Random().nextInt(999999);//生成隨機數(shù),最大為999999
if(code < 100000){
code = code + 100000;//保證隨機數(shù)為6位數(shù)字
}
// 其他情況
}else{
throw new RuntimeException("只能生成4位或6位數(shù)字驗證碼");
}
return code;
}
/**
* 隨機生成指定長度字符串驗證碼
* @param length 長度
* @return
*/
public static String generateValidateCode4String(int length){
Random rdm = new Random();
String hash1 = Integer.toHexString(rdm.nextInt());
String capstr = hash1.substring(0, length);
return capstr;
}
}1.3.4 手機驗證碼登錄-- 發(fā)送驗證碼
兩次ajax請求:
1. 登錄頁面輸入手機號,點擊【獲取驗證碼】按鈕,頁面發(fā)送ajax請求,在服務(wù)端調(diào)用短信服務(wù)API給指定手機號發(fā)送驗證碼短信
2. 在登錄頁面輸入驗證碼,點擊【登錄】按鈕,發(fā)送ajax請求,在服務(wù)端處理登錄請求
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user, HttpSession session){
// 1.獲取手機號
String phone = user.getPhone();
if(StringUtils.isEmpty(phone)){
return R.error("短信發(fā)送失敗");
}
// 2.隨機生成四位驗證碼
String code = ValidateCodeUtils.generateValidateCode(4).toString();
// 3.調(diào)用阿里云提供的短信服務(wù)
SMSUtils.sendMessage("張靖奇","",phone,code);
// 4.需要將生成的驗證碼保存到session中
session.setAttribute(phone,code);
return R.success("驗證碼短信發(fā)送成功");
}1.3.5 手機驗證碼登錄-- 驗證驗證碼
// 其實傳過來的phone:xxxx,code:xxx 也可以用map集合接收
@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session) {
log.info(map.toString());
// 1. 獲取手機號
String phone = map.get("phone").toString();
// 2. 獲取驗證碼
String code = map.get("code").toString();
// 3. 從Session中獲取保存的驗證碼
Object codeInSession = session.getAttribute(phone);
// 4. 進行驗證碼比對(頁面提交的驗證碼和Session中保存的驗證碼比對)
if (codeInSession != null && codeInSession.equals(code)) {
// 5.對比成功,說明登錄成功
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getPhone,phone);
User user = userService.getOne(queryWrapper);
if (user==null){
// 6. 如果新用戶,自動注冊
user = new User();
user.setPhone(phone);
user.setStatus(1);
userService.save(user);
}
session.setAttribute("user",user.getId());
return R.success(user);
}
return R.error("登錄失敗");
}到此這篇關(guān)于SpringBoot實現(xiàn)短信發(fā)送及手機驗證碼登錄的文章就介紹到這了,更多相關(guān)SpringBoot 手機驗證碼登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatisPlus-QueryWrapper多條件查詢及修改方式
這篇文章主要介紹了MyBatisPlus-QueryWrapper多條件查詢及修改方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式
這篇文章主要介紹了PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08

