您好,登錄后才能下訂單哦!
這篇文章主要介紹js+java怎么實現登錄滑動圖片驗證,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
下面是做出來的效果:
實現思路:所有的圖片數據,驗證全部由后端來做。前端調用接口,后端會返回兩張經過base64加密的圖片信息,分別是背景圖片和滑塊圖片,前端滑動滑塊以后將X方向的滑動距離傳回后端做驗證,驗證成功以后再做后續的登錄邏輯驗證,以下是完整的過程:
獲取背景圖,我這邊是在FTP上放了10張圖片,隨機獲取一張。
@LogAnnotation(description = "web獲取滑動圖片信息") @ApiOperation(value = "web獲取滑動圖片信息", httpMethod = "POST", response = Result.class, notes = "") @RequiresPermissions(value = "code/picture/msg") @RequestMapping(value = "code/picture/msg", method = RequestMethod.POST) @ResponseBody public Response getPictureCode(HttpServletRequest request) { Map<String, Object> pictureMap = new HashMap<>(); try { //隨機獲取需要切成的圖片形狀 Integer templateNum = new Random().nextInt(10) + 1; String randomStr = String.valueOf(templateNum); if(templateNum < 10){ randomStr = "0"+randomStr; } InputStream tempInputStream = FileUtils.downloadFtpFile(Constant.POCTURE_CHECK_PATH,randomStr+".jpg"); //根據源圖片和摳圖形狀生成新的圖片信息以流的形式返回到前端 pictureMap = VerifyImageUtil.getVerifyImage(tempInputStream); //將剪裁好了以后的圖片信息以當前時間戳為key,存入redis(這一步是為了對圖片信息做過期處理,根據自己需求做) String tempTime = String.valueOf(System.currentTimeMillis()); redisUtils.hset(Constant.REDIS_LOGIN_PICTURE_CODE, tempTime,pictureMap.get("locationX").toString(),60); pictureMap.put("tempTime",tempTime); //移出隨機生成的摳圖位置坐標,不返回給前端 pictureMap.remove("locationX"); return new ObjectResponse<Map<String, Object>>(pictureMap); }catch(Exception e){ logger.error("code/picture/msg", e); return new FailedResponse(); } }
FTP下載方法代碼
public static FTPClient ftpLogin(){ String ip = p.getProperty("ftp的ip"); String username = p.getProperty("ftp的user"); String password = p.getProperty("ftp的pwd"); int ftpPort = Integer.parseInt(p.getProperty("ftp的port")); FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(ip , ftpPort );// 連接FTP服務器 ftpClient.login(username , password );// 登陸FTP服務器 if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) { ftpClient.disconnect(); } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return ftpClient; } public static InputStream downloadFtpFile(String ftpPath, String fileName) { FTPClient ftpClient = ftpLogin(); try { ftpClient.setControlEncoding("UTF-8"); // 中文支持 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); ftpClient.changeWorkingDirectory(ftpPath); InputStream inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes("UTF-8"), "ISO-8859-1")); //ftpClient.completePendingCommand(); return inputStream; } catch (Exception e) { e.printStackTrace(); }finally { try { ftpClient.logout(); } catch (IOException e) { e.printStackTrace(); } } return null; }
摳圖工具類VerifyImageUtil
public class VerifyImageUtil { /** * 源文件寬度 */ private static int ORI_WIDTH = 296; /** * 源文件高度 */ private static int ORI_HEIGHT = 182; /** * 模板圖寬度 */ private static int CUT_WIDTH = 50; /** * 模板圖高度 */ private static int CUT_HEIGHT = 50; /** * 摳圖凸起圓心 */ private static int circleR = 6; /** * 摳圖內部矩形填充大小 */ private static int RECTANGLE_PADDING = 6; /** * 摳圖的邊框寬度 */ private static int SLIDER_IMG_OUT_PADDING = 1; /** * 根據傳入的路徑生成指定驗證碼圖片 * * @param filePath * @return * @throws IOException */ public static Map<String, Object> getVerifyImage(InputStream filePath) throws IOException { BufferedImage srcImage = ImageIO.read(filePath); int locationX = CUT_WIDTH + new Random().nextInt(srcImage.getWidth() - CUT_WIDTH * 2); int locationY = CUT_HEIGHT + new Random().nextInt(srcImage.getHeight() - CUT_HEIGHT) / 2; BufferedImage markImage = new BufferedImage(CUT_WIDTH,CUT_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR); int[][] data = getBlockData(); cutImgByTemplate(srcImage, markImage, data, locationX, locationY); Map<String, Object> resultMap = new HashMap<>(); //放入背景圖的加密信息 resultMap.put("srcImage",getImageBASE64(srcImage)); //放入滑塊圖的加密信息 resultMap.put("markImage",getImageBASE64(markImage)); //放入摳圖位置的X方向的信息,用于驗證滑塊位置是否正確 resultMap.put("locationX",locationX); //放入摳圖位置的Y方向的信息,用于前端控制定位信息 resultMap.put("locationY",locationY); return resultMap; } /** * 生成隨機滑塊形狀 * <p> * 0 透明像素 * 1 滑塊像素 * 2 陰影像素 * @return int[][] */ private static int[][] getBlockData() { int[][] data = new int[CUT_WIDTH][CUT_HEIGHT]; Random random = new Random(); //(x-a)²+(y-b)²=r² //x中心位置左右5像素隨機 double x1 = RECTANGLE_PADDING + (CUT_WIDTH - 2 * RECTANGLE_PADDING) / 2.0 - 5 + random.nextInt(10); //y 矩形上邊界半徑-1像素移動 double y1_top = RECTANGLE_PADDING - random.nextInt(3); double y1_bottom = CUT_HEIGHT - RECTANGLE_PADDING + random.nextInt(3); double y1 = random.nextInt(2) == 1 ? y1_top : y1_bottom; double x2_right = CUT_WIDTH - RECTANGLE_PADDING - circleR + random.nextInt(2 * circleR - 4); double x2_left = RECTANGLE_PADDING + circleR - 2 - random.nextInt(2 * circleR - 4); double x2 = random.nextInt(2) == 1 ? x2_right : x2_left; double y2 = RECTANGLE_PADDING + (CUT_HEIGHT - 2 * RECTANGLE_PADDING) / 2.0 - 4 + random.nextInt(10); double po = Math.pow(circleR, 2); for (int i = 0; i < CUT_WIDTH; i++) { for (int j = 0; j < CUT_HEIGHT; j++) { //矩形區域 boolean fill; if ((i >= RECTANGLE_PADDING && i < CUT_WIDTH - RECTANGLE_PADDING) && (j >= RECTANGLE_PADDING && j < CUT_HEIGHT - RECTANGLE_PADDING)) { data[i][j] = 1; fill = true; } else { data[i][j] = 0; fill = false; } //凸出區域 double d3 = Math.pow(i - x1, 2) + Math.pow(j - y1, 2); if (d3 < po) { data[i][j] = 1; } else { if (!fill) { data[i][j] = 0; } } //凹進區域 double d4 = Math.pow(i - x2, 2) + Math.pow(j - y2, 2); if (d4 < po) { data[i][j] = 0; } } } //邊界陰影 for (int i = 0; i < CUT_WIDTH; i++) { for (int j = 0; j < CUT_HEIGHT; j++) { //四個正方形邊角處理 for (int k = 1; k <= SLIDER_IMG_OUT_PADDING; k++) { //左上、右上 if (i >= RECTANGLE_PADDING - k && i < RECTANGLE_PADDING && ((j >= RECTANGLE_PADDING - k && j < RECTANGLE_PADDING) || (j >= CUT_HEIGHT - RECTANGLE_PADDING - k && j < CUT_HEIGHT - RECTANGLE_PADDING +1))) { data[i][j] = 2; } //左下、右下 if (i >= CUT_WIDTH - RECTANGLE_PADDING + k - 1 && i < CUT_WIDTH - RECTANGLE_PADDING + 1) { for (int n = 1; n <= SLIDER_IMG_OUT_PADDING; n++) { if (((j >= RECTANGLE_PADDING - n && j < RECTANGLE_PADDING) || (j >= CUT_HEIGHT - RECTANGLE_PADDING - n && j <= CUT_HEIGHT - RECTANGLE_PADDING ))) { data[i][j] = 2; } } } } if (data[i][j] == 1 && j - SLIDER_IMG_OUT_PADDING > 0 && data[i][j - SLIDER_IMG_OUT_PADDING] == 0) { data[i][j - SLIDER_IMG_OUT_PADDING] = 2; } if (data[i][j] == 1 && j + SLIDER_IMG_OUT_PADDING > 0 && j + SLIDER_IMG_OUT_PADDING < CUT_HEIGHT && data[i][j + SLIDER_IMG_OUT_PADDING] == 0) { data[i][j + SLIDER_IMG_OUT_PADDING] = 2; } if (data[i][j] == 1 && i - SLIDER_IMG_OUT_PADDING > 0 && data[i - SLIDER_IMG_OUT_PADDING][j] == 0) { data[i - SLIDER_IMG_OUT_PADDING][j] = 2; } if (data[i][j] == 1 && i + SLIDER_IMG_OUT_PADDING > 0 && i + SLIDER_IMG_OUT_PADDING < CUT_WIDTH && data[i + SLIDER_IMG_OUT_PADDING][j] == 0) { data[i + SLIDER_IMG_OUT_PADDING][j] = 2; } } } return data; } /** * 裁剪區塊 * 根據生成的滑塊形狀,對原圖和裁剪塊進行變色處理 * @param oriImage 原圖 * @param targetImage 裁剪圖 * @param blockImage 滑塊 * @param x 裁剪點x * @param y 裁剪點y */ private static void cutImgByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] blockImage, int x, int y) { for (int i = 0; i < CUT_WIDTH; i++) { for (int j = 0; j < CUT_HEIGHT; j++) { int _x = x + i; int _y = y + j; int rgbFlg = blockImage[i][j]; int rgb_ori = oriImage.getRGB(_x, _y); // 原圖中對應位置變色處理 if (rgbFlg == 1) { //摳圖上復制對應顏色值 targetImage.setRGB(i,j, rgb_ori); //原圖對應位置顏色變化 oriImage.setRGB(_x, _y, rgb_ori & 0x363636); } else if (rgbFlg == 2) { targetImage.setRGB(i, j, Color.WHITE.getRGB()); oriImage.setRGB(_x, _y, Color.GRAY.getRGB()); }else if(rgbFlg == 0){ //int alpha = 0; targetImage.setRGB(i, j, rgb_ori & 0x00ffffff); } } } } /** * 隨機獲取一張圖片對象 * @param path * @return * @throws IOException */ public static BufferedImage getRandomImage(String path) throws IOException { File files = new File(path); File[] fileList = files.listFiles(); List<String> fileNameList = new ArrayList<>(); if (fileList!=null && fileList.length!=0){ for (File tempFile:fileList){ if (tempFile.isFile() && tempFile.getName().endsWith(".jpg")){ fileNameList.add(tempFile.getAbsolutePath().trim()); } } } Random random = new Random(); File imageFile = new File(fileNameList.get(random.nextInt(fileNameList.size()))); return ImageIO.read(imageFile); } /** * 將IMG輸出為文件 * @param image * @param file * @throws Exception */ public static void writeImg(BufferedImage image, String file) throws Exception { byte[] imagedata = null; ByteArrayOutputStream bao=new ByteArrayOutputStream(); ImageIO.write(image,"png",bao); imagedata = bao.toByteArray(); FileOutputStream out = new FileOutputStream(new File(file)); out.write(imagedata); out.close(); } /** * 將圖片轉換為BASE64 * @param image * @return * @throws IOException */ public static String getImageBASE64(BufferedImage image) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageIO.write(image,"png",out); //轉成byte數組 byte[] bytes = out.toByteArray(); BASE64Encoder encoder = new BASE64Encoder(); //生成BASE64編碼 return encoder.encode(bytes); } /** * 將BASE64字符串轉換為圖片 * @param base64String * @return */ public static BufferedImage base64StringToImage(String base64String) { try { BASE64Decoder decoder=new BASE64Decoder(); byte[] bytes1 = decoder.decodeBuffer(base64String); ByteArrayInputStream bais = new ByteArrayInputStream(bytes1); return ImageIO.read(bais); } catch (IOException e) { e.printStackTrace(); } return null; } }
前端收到請求成功返回信息以后,對數據做解析
// 設置圖片的src屬性 $("#背景圖的ID").attr("src", "data:image/png;base64," + result.datas.srcImage); $("#滑塊圖的ID").attr("src", "data:image/png;base64," + result.datas.markImage); $("#滑塊圖的ID").css("top", result.datas.locationY); /* 初始化按鈕拖動事件 */ // 鼠標點擊事件 $("#滑塊拖動條").mousedown(function(e) { e = e || window.event; // 鼠標在滑塊按下切換滑塊背景 var left = e.pageX;//記錄鼠標按下時的坐標 X軸值 var num = 0; // 鼠標移動事件 document.onmousemove = function(e) { var nowLeft = e.pageX; num = nowLeft-left; if(num <= 0){ num = 0; }else if(num >= 251){ num= 251; } $("#滑塊拖動條").css("width", (42+num) + "px"); $("#滑塊拖動條圖片").css("left", (num) + "px"); $("#滑塊拖動條").css("background-color", "#3c55ff"); }; // 鼠標松開事件 document.onmouseup = function(e) { left = 0; document.onmousemove = null; document.onmouseup = null; //松開以后進行后續的驗證...... }; });
以上是“js+java怎么實現登錄滑動圖片驗證”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。