我們項目開發中比較通用的登錄方式是用賬號密碼登錄,但實際生活中短信登錄的方式是大家所常用的。
下面的文章,前三步我先進行了短信登錄的實現,最后一步對其進行了異常處理封裝的細節優化。
實現驗證碼登錄流程分析 1)發送驗證碼 用戶在提交手機號后,會校驗手機號是否合法,如果不合法,則要求用戶重新輸入手機號。
如果手機號合法,后臺此時生成對應的驗證碼,同時將驗證碼進行保存,然后再通過短信的方式將驗證碼發送給用戶。
2)短信驗證碼登錄、注冊 用戶需輸入收到的驗證碼及關聯的手機號碼。服務器后臺會從當前的Session中提取先前存儲的驗證碼,并與用戶所輸入的進行比對。若兩者不匹配,用戶將無法完成驗證過程。若驗證碼相符,系統將依據用戶輸入的手機號碼在數據庫中進行用戶查詢。若查詢結果顯示該手機號尚未注冊,系統將自動創建新的用戶賬戶,并將基礎信息存入數據庫。無論用戶是已存在或是新注冊,系統都會更新 Session 信息,保存用戶的登錄憑證,以便用戶能夠順利進行后續操作并隨時訪問其賬戶信息。
代碼實現驗證碼發送 這里我使用 MyBatisX 實現項目的初始化。
1)正則表達式類 使用正則表達式分別對手機號、密碼、驗證碼進行校驗。
正則表達式可以去網上找,我這里提供下我的實現方式,可以作為參考。
public class RegexPatterns { /** * 手機號正則 */ public static final String PHONE_REGEX="1\\d{10}" ; /** * 郵箱正則 */ public static final String EMAIL_REGEX="/^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$/" ; /** * 驗證碼正則 */ public static final String VERIFY_CODE_REGEX="^[a-zA-Z\\d]{6}$" ; }
2)正則校驗工具類 對 Controller 層傳入的手機號進行校驗。
滿足手機號正則表達式,手機號 11 位,并且只能為數字,才能校驗通過 。
這里我使用的是 Hutool 工具類來校驗手機號和驗證碼是否合法。
我貼一下 Hutool 的官網,有需要更加深層次了解的小伙伴可以訪問下哦!
Hutool 官網:https://doc.hutool.cn/pages/index/
public class RegexUtils { /** * 校驗手機號是否合法 * @param phone * @return */ public static boolean isPhoneInvalid(String phone){ boolean matches = phone.matches(RegexPatterns.PHONE_REGEX); return matches; } /** * 校驗驗證碼是否合法 * @param code * @return */ public boolean isCodeInvalid(String code){ boolean matches = code.matches(RegexPatterns.VERIFY_CODE_REGEX); return matches; } }
3)Controller 層 @GetMapping("/code" ) public boolean SendCode(String phone, HttpSession session){ boolean b = userService.sendCode(phone, session); return b; }
4)Service 層 首先,系統會將用戶輸入的手機號通過正則表達式校驗工具類進行驗證,確保其格式正確無誤。一旦手機號通過校驗,程序便會自動生成一個隨機驗證碼,并將其安全地存儲在服務器的 Session 中。為了便于開發者實時監控驗證碼的生成和發送狀態,系統特別設計了在控制臺以 debug 模式輸出驗證碼的功能,從而確保了整個驗證流程的透明度和可追蹤性。
@Resource private UserService userService; public boolean sendCode(String phone, HttpSession session) { //1、校驗手機號是否合法 if (!RegexUtils.isPhoneInvalid(phone)) { return false ; } //2、生成隨機驗證嗎 String code = RandomUtil.randomNumbers(6); //3、保存驗證碼 session.setAttribute("code" ,code); //4、打印日志 log.debug("發送短信驗證碼成功,驗證碼:{}" ,code); return true ; }
注意:這里需要開啟 debug 日志
controller 層中加入@Slf4j
注解
logging: level: com.example: debug# 開啟debug日志
結果:
實現驗證碼登錄注冊 短信驗證登錄注冊邏輯:
1、校驗手機號
2、校驗驗證碼(取出 Session 中保存的驗證碼與表單中的輸入的驗證碼嗎進行比較)
3、不一致:報錯
4、一致:根據手機號查詢用戶
5、判斷用戶是否存在
6、不存在,根據手機號創建新用戶并保存
7、保存用戶信息到 Session 中
1)Controller 層 我們登錄需要獲取兩個參數,用戶名和手機號,根據手機號來創建用戶名。
@PostMapping("/login" ) public boolean login(LoginFormDTO loginFormDTO, HttpSession session){ boolean login = userService.Login(loginFormDTO, session); return login; }
為了使代碼更加美觀,創建一個參數封裝類。
/** * 用戶登錄請求參數封裝類 */ @Data public class LoginFormDTO { private String code; private String phone; }
2)Servcie 層 /** * 用戶登錄 * @param loginFormDTO * @param session * @return */ @Override public boolean Login(LoginFormDTO loginFormDTO, HttpSession session) { //1、首先校驗手機號和驗證碼是否合法 String phone = loginFormDTO.getPhone(); if (!RegexUtils.isPhoneInvalid(phone)){ return false ; } //2、校驗驗證碼 Object cachecode = session.getAttribute("code" ); String dtoCode = loginFormDTO.getCode(); if (dtoCode==null&&!dtoCode.equals(cachecode)) { return false ; } //3、根據手機號查詢用戶信息 QueryWrapper<User> queryWrapper=new QueryWrapper<User>(); queryWrapper.eq("phone" , phone); //4、根據查詢條件查詢數據庫中滿足以上條件的用戶 User user = userMapper.selectOne(queryWrapper); if (user==null) { //創建用戶 user=CreateUser(phone); } //5、保存用戶信息到session中 session.setAttribute("user" ,user); return true ; }
將創建用戶的這段代碼單獨封裝為一個函數。
/** * 創建用戶 * @param phone * @return */ private User CreateUser(String phone){ User user = new User(); user.setPhone(phone); user.setNickName(RandomUtil.randomString(10)); //保存用戶 save(user); return user; }
發送驗證碼
get http://localhost:8080/api/user/code?phone=13177576913
校驗驗證碼并登錄
post http://localhost:8080/api/user/login?phone=13177576913 &code=686422
運行結果:
優化:全局通用返回對象 前面我的測試前端返回的數據都太過單調,因為這是一個功能的實現,并不是做一個完整的項目,但這樣看起來確實不太美觀。
所以這里使用 ==》全局統一 API 響應框架 ==》對整個接口進行統一的異常處理封裝,這樣就不需要寫那么多的異常處理類了。
1)引入依賴 使用rest-api-spring-boot-starter
這個依賴,不用打開 Redis ,但這個依賴需要加上。
<!--RestfulAPI--> <dependency> <groupId>cn.soboys</groupId> <artifactId>rest-api-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2)注解 啟動類上加上這個@EnableRestFullApi
注解。
只需要引入依賴和加上注解這兩步,Log 日志就變得與上面沒優化前的不一樣了。
注意:這里的端口號是 8000,也就是說使用這個依賴必須要 8000 端口,我們在配置文件中所設置的 Web 端口沒有用了,無法自定義端口
運行后,通過 Postman 測試,測試結果如下圖所示:
3)用戶信息脫敏 我們這里進行用戶脫敏,將返回對象單獨封裝。
@Data public class UserDTO { private Long id; private String nickName; private String icon; }
修改登錄login
方法中的下面所示內容。
/** * copyProperties:屬性拷貝——把user中的屬性字動拷貝到UserDTO中 * BeanUtils:使用的是包cn.hutool.core.bean下的工具類 */ //5、保存用戶信息到session中 UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class); session.setAttribute("user" , userDTO);
最終,如下圖所示成功返回三個信息。
以上,就是今天的分享,希望對大家有幫助。
該文章在 2024/4/12 23:15:39 編輯過