簡訊驗證
一、基於Session
1、登入流程
1)傳送驗證碼
使用者在提交手機號後,會校驗手機號是否合法,如果不合法,則要求使用者重新輸入手機號
如果手機號合法,後臺此時生成對應的驗證碼,同時將驗證碼進行儲存,然後再透過簡訊的方式將驗證碼傳送給使用者
2)簡訊驗證碼登入、註冊
使用者將驗證碼和手機號進行輸入,
後臺從session中拿到當前驗證碼,然後和使用者輸入的驗證碼進行校驗,
如果不一致,則無法透過校驗,
如果一致,則後臺根據手機號查詢使用者,
如果使用者不存在,則為使用者建立賬號資訊,儲存到資料庫。
無論是否存在,都會將使用者資訊儲存到session中,方便後續獲得當前登入資訊
2、實現驗證碼傳送
使用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位,並且只能為數字,才能校驗透過
官網: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日誌
結果:
3、實現驗證碼登入註冊
簡訊驗證登入註冊邏輯:
- 校驗手機號
- 校驗驗證碼
- 取出session中儲存的驗證碼與表單中的輸入的驗證碼嗎進行比較
- 不一致:報錯
- 一致:根據手機號查詢使用者
- 判斷使用者是否存在
- 不存在,根據手機號建立新使用者並儲存
- 使用者是憑空建立的,所以密碼可以沒有,
- 使用者呢稱和頭像都是隨機預設的
- 儲存使用者資訊到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)service層
/** * 使用者登入 * @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
結果:
4、最佳化一:全域性通用返回物件
前面我的測試前端返回的資料都太過單調,因為這是一個功能的實現,並不是做一個完整的專案,但這樣看起來確實不太美觀
所以這裡使用==全域性統一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埠沒有用了,無法自定義埠
執行
我們先進行使用者脫敏
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);
結果這裡就不說了,成功返回三個資訊