SpringBoot實現(xiàn)短信發(fā)送及手機驗證碼登錄
一、短信發(fā)送
1.1 阿里云短信服務
也可以在下面這個地方查看短信服務
1.1.1 設置短信簽名
短信簽名就是短信發(fā)送者的署名,表示發(fā)送方的身份
1.1.2 模板管理
申請下來之后可以點擊詳情進行查看
其中模板CODE是自動生成的,不用管,重點是模板的內(nèi)容
1.1.3 設置AccessKey
創(chuàng)建新的用戶
勾選上之后,我們在編程代碼中就能使用
當我們創(chuàng)建用戶成功后,就生成了一對AccessKey,即AccessKey ID(用戶名) 與AccessKey Secret(密碼)
很多人在這里的時候不小心沒截圖或者沒保存就關了,丟失了AccessKey,但是不要緊,還可以再次創(chuàng)建
還有就是如果別人知道了我們的AccessKey,那別人使用的時候會就花我們的錢。我們也可以把泄露的AccessKey禁用
之后再新增授權。這次授權的意思就是僅僅授予有關短信服務的,即是我們泄露了,別人也只能操作短信服務,對我們的影響很小。
1.2 短信發(fā)送——代碼開發(fā)
參照官方文檔即可
1.2.1 導入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); // 我們在阿里云設置的簽名 request.setSignName(signName); // 我們在阿里云設置的模板 request.setTemplateCode(templateCode); // 在設置模板的時候有一個占位符 request.setTemplateParam("{\"code\":\""+param+"\"}"); // request.setPhoneNumbers("1368846****");//接收短信的手機號碼 // request.setSignName("阿里云");//短信簽名名稱 // request.setTemplateCode("SMS_20933****");//短信模板CODE // request.setTemplateParam("張三");//短信模板變量對應的實際值 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服務器進行配置),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")); // 通過輸出流的方式向客戶端響應數(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請求,在服務端調(diào)用短信服務API給指定手機號發(fā)送驗證碼短信
2. 在登錄頁面輸入驗證碼,點擊【登錄】按鈕,發(fā)送ajax請求,在服務端處理登錄請求
@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)用阿里云提供的短信服務 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("登錄失敗"); }
到此這篇關于SpringBoot實現(xiàn)短信發(fā)送及手機驗證碼登錄的文章就介紹到這了,更多相關SpringBoot 手機驗證碼登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MyBatisPlus-QueryWrapper多條件查詢及修改方式
這篇文章主要介紹了MyBatisPlus-QueryWrapper多條件查詢及修改方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式
這篇文章主要介紹了PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08