基本思路
獲取驗證碼接口
驗證碼操作用了com.pig4cloud.plugin的captcha-core這個庫。
- AccountControl的"/checkCode"接口代碼,通過ArithmeticCaptcha生成一張驗證碼圖片,通過text()函數得到驗證碼的答案保存到變量code,然后把圖片轉為base64方便傳輸保存到變量checkCodeBase64 。
- 把code作為參數傳入函數saveCheckCode,把函數返回結果保存到變量checkCodeKey 。
- 創建一個Map,checkCodeBase64和checkCodeKey放進去,然后丟給getSuccessResponseVO()當作響應消息返回。
@RequestMapping("/checkCode")public ResponseVO checkCode(){//生成驗證碼ArithmeticCaptcha captcha = new ArithmeticCaptcha(100,42);//獲取驗證碼String code = captcha.text();//生成base64String checkCodeBase64 = captcha.toBase64();//把驗證碼存入redisString checkCodeKey = redisComponet.saveCheckCode(code);Map<String,String> result = new HashMap<>();result.put("checkCode",checkCodeBase64);result.put("checkCodeKey",checkCodeKey);return getSuccessResponseVO(result);}
- saveCheckCode函數負責把驗證碼答案code保存到redis,生成一個隨機的 UUID作為存到redis的key,把這個key返回出去。
public String saveCheckCode(String code){String checkCodeKey = UUID.randomUUID().toString();redisUtils.setex(Constants.REDIS_KEY_CHECK_CODE+checkCodeKey,code,Constants.REDIS_KEY_EXPIRE_ONE_MIN);return checkCodeKey;
}
接口執行結果:
用戶注冊
- 根據傳入的驗證碼答案checkCode判斷是否與redis儲存的值相等。
- 驗證碼通過后執行register服務函數。
- 執行完try的代碼,執行finally代碼刪除redis相應的鍵值。
@RequestMapping("/register")
public ResponseVO register(@NotEmpty @Email @Size(max = 150) String email,@NotEmpty @Size(max = 20) String nickName,@NotEmpty @Pattern(regexp = Constants.REGEX_PASSWORD) String registerPassword,@NotEmpty String checkCodeKey,@NotEmpty String checkCode){try {if(!checkCode.equalsIgnoreCase(redisComponet.getCheckeCode(checkCodeKey))){throw new BusinessException("圖片驗證碼不正確");}userInfoService.register(email,nickName,registerPassword);return getSuccessResponseVO(null);} catch (BusinessException e) {throw new RuntimeException(e);} finally {redisComponet.cleanCheckCode(checkCodeKey);}
}
- 檢查郵箱和昵稱是否已存在。
- mybatis操作數據庫創建新注冊的用戶信息。
@Override
public void register(String email, String nickName, String registerPassword) throws BusinessException {UserInfo userInfo = this.userInfoMapper.selectByEmail(email);if(null!=userInfo){throw new BusinessException("郵箱已被注冊");}UserInfo nickNameUser = this.userInfoMapper.selectByNickName(nickName);if(null!=nickNameUser){throw new BusinessException("昵稱已被注冊");}userInfo = new UserInfo();String userId = StringTools.getRandomNumber(Constants.USERID_LENGTH);userInfo.setUserId(userId);userInfo.setEmail(email);userInfo.setNickName(nickName);userInfo.setPassword(StringTools.encodeByMd5(registerPassword));userInfo.setJoinTime(new Date());userInfo.setStatus(UserStatusEnum.NORMAL.getCode());userInfo.setTotalCoin(0);this.userInfoMapper.insert(userInfo);}
執行結果:
輸入對應的參數
注冊成功
檢查數據庫
登錄接口
- 傳入email、password、checkCodeKey和checkCode,校驗驗證碼。
- 獲取登錄的ip地址,向登錄服務函數login傳入email、password和ip返回dto對象,把該dto對象保存。
- SaveTokenToCookie函數作用是保存dto里的token到瀏覽器中,方便前端獲取。
- 執行完try的代碼,執行finally代碼刪除redis相應的鍵值。
@RequestMapping("/login")
public ResponseVO login(HttpServletResponse response,@NotEmpty @Email String email,@NotEmpty String password,@NotEmpty String checkCodeKey,@NotEmpty String checkCode){try {if(!checkCode.equalsIgnoreCase(redisComponet.getCheckeCode(checkCodeKey))){throw new BusinessException("圖片驗證碼不正確");}String ip = getIpAddr();TokenUserInfoDTO tokenUserInfoDTO = userInfoService.login(email ,password,ip);SaveTokenToCookie(response,tokenUserInfoDTO.getToken());return getSuccessResponseVO(tokenUserInfoDTO);} catch (BusinessException e) {throw new RuntimeException(e);} finally {redisComponet.cleanCheckCode(checkCodeKey);}
}
獲取用戶IP地址的函數
protected String getIpAddr() {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String ip = request.getHeader("x-forwarded-for");if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {// 多次反向代理后會有多個ip值,第一個ip才是真實ipif (ip.indexOf(",") != -1) {ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;
}
在瀏覽器保存token
protected void SaveTokenToCookie(HttpServletResponse response,String token) {Cookie cookie = new Cookie(Constants.TOKEN_WEB,token);cookie.setMaxAge(Constants.REDIS_KEY_EXPIRE_ONE_DAY / 1000 * 7);cookie.setPath("/");response.addCookie(cookie);
}
- 檢驗郵箱、密碼和用戶狀態,拋出對應的異常。
- 登錄信息無誤,根據用戶ID更新ip和最新登錄時間。
- 對象拷貝,將一個對象userInfo的屬性復制到DTO對象中(不會復制DTO中沒有的屬性)。
- 把DTO對象保存到redis中,token的內容是保存到redis的key值。
@Override
public TokenUserInfoDTO login(String email, String password, String ip) throws BusinessException {UserInfo userInfo = this.userInfoMapper.selectByEmail(email);if(null==userInfo || !userInfo.getPassword().equals(StringTools.encodeByMd5(password))){throw new BusinessException("用戶名或密碼錯誤");}if(UserStatusEnum.FORBIDDEN.getCode().equals(userInfo.getStatus())){throw new BusinessException("用戶已被禁用");}UserInfo updateInfo = new UserInfo();updateInfo.setLastLogin(new Date());updateInfo.setLastIp(ip);this.userInfoMapper.updateByUserId(updateInfo,userInfo.getUserId());TokenUserInfoDTO tokenUserInfoDTO = CopyTools.copy(userInfo, TokenUserInfoDTO.class);redisComponet.saveTokenInfo(tokenUserInfoDTO);return tokenUserInfoDTO;
}
執行結果: