springboot uniapp 验证码滑块

发布于:2024-04-14 ⋅ 阅读:(91) ⋅ 点赞:(0)

 java

  private final Map<String, Integer> sliderPositions = new HashMap<>();

    @GetMapping("/captcha")
    public ResponseEntity<byte[]> getCaptcha() {
        try {
            // Width of the slider
            int sliderWidth = 50;
            // Total captcha width
//            int imageWidth = 200;
            int imageWidth = 300;
            // Total captcha height
            int imageHeight = 100;
            int sliderPosition = ThreadLocalRandom.current().nextInt(10, imageWidth - sliderWidth - 10);

            BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = image.createGraphics();
            // Background
            graphics.setColor(Color.LIGHT_GRAY);
            graphics.fillRect(0, 0, imageWidth, imageHeight);
            // Slider area
            graphics.setColor(Color.RED);
            graphics.fillRect(sliderPosition, 0, sliderWidth, imageHeight);
            graphics.dispose();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);

            // Store the slider position for validation
            String sessionId = "user-session-id"; // This should be unique per user/session
            sliderPositions.put(sessionId, sliderPosition);

            return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).body(baos.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("/verify")
    public ResponseEntity<String> verifyCaptcha(@RequestBody VerifyRequest request) {
        String sessionId = "user-session-id"; // This should match the session used in getCaptcha
        if (!sliderPositions.containsKey(sessionId)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Session not found");
        }

        int correctPosition = sliderPositions.get(sessionId);
        if (Math.abs(request.getSlideDistance() - correctPosition) <= 5) { // Allow some margin
            return ResponseEntity.ok("Verified");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Verification failed");
        }
    }

    static class VerifyRequest {
        private int slideDistance;

        public int getSlideDistance() {
            return slideDistance;
        }

        public void setSlideDistance(int slideDistance) {
            this.slideDistance = slideDistance;
        }
    }

uniapp

/components/SliderCaptcha.vue

<template>
  <view class="container">
	  <!-- widthFix -->
    <image :src="captchaSrc" class="captcha" mode="heightFix" @click="fetchCaptcha"/>
    <view class="slider" @touchstart="startMove" @touchmove="onMove" @touchend="endMove" :style="{ left: sliderPosition + 'px' }">|||</view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      startX: 0,
      currentX: 0,
      sliderPosition: 0,
      captchaSrc: '',
    };
  },
  mounted() {
    this.fetchCaptcha();
  },
  methods: {
    fetchCaptcha() {
      // 注意替换成你的实际后端地址
      this.captchaSrc = 'http://localhost:8080/fapi/home/captcha?' + new Date().getTime(); // 防止图片缓存
      this.sliderPosition = 0; // 重置滑块位置
    },
    startMove(event) {
      this.startX = event.touches[0].clientX;
      this.currentX = this.sliderPosition;
    },
    onMove(event) {
      const moveX = event.touches[0].clientX - this.startX;
      let newX = this.currentX + moveX;

      // 限制滑块移动范围
      newX = Math.max(0, Math.min(300 - 50, newX)); // 假设背景图宽200px,滑块宽50px
      this.sliderPosition = newX;
    },
    endMove() {
      // 向后端发送滑块位置进行验证
      uni.request({
        url: 'http://localhost:8080/fapi/home/verify', // 注意替换成你的实际后端地址
        method: 'POST',
        data: {
          slideDistance: this.sliderPosition,
        },
        success: (res) => {
          if (res.statusCode === 200) {
            uni.showToast({ title: '验证成功', icon: 'success' });
          } else {
            uni.showToast({ title: '验证失败', icon: 'none' });
          }
          this.fetchCaptcha(); // 重新加载验证码
        },
      });
    },
  },
};
</script>


<style lang="scss" scoped>
/* .container {
  position: relative;
  width: 200px; 
  height: 100px; 
  margin: 0 auto;
}
.captcha {
  width: 100%;
}
.slider {
  position: absolute;
  top: 0;
  width: 50px;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  color: #fff;
  text-align: center;
  line-height: 100px; 
} */

.container {
  position: relative;
  width: 300px; 
  height: 100px; 
  /* margin: 0 auto; */
}
.captcha {
  height: 100px;
}
.slider {
  position: absolute;
  top: 0;
  width: 50px;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  color: #fff;
  text-align: center;
  line-height: 100px; 
}
</style>

CaptchaPopup.vue

<template>
	<view class="container">
		<!-- <button @click="showPopup = true">显示滑动验证码</button> -->
		<!-- v-model="showPopup" -->
		<!-- <slider-captcha /> -->
		<!-- <u-popup></u-popup> -->
		<!--  <u-popup :v-model="true">
	  			出淤泥而不染,濯清涟而不妖
	  </u-popup> -->
		<u-popup :show="show" mode="center">
			<view style="margin-left: 0rpx;">
				<slider-captcha />
			</view>
		</u-popup>
		<u-button @click="show = true">打开</u-button>
	</view>
</template>

<script>
	import SliderCaptcha from '@/components/SliderCaptcha.vue';
	// import Popup from '@/components/uni-popup/uni-popup.vue'; // 确保路径正确

	export default {
		components: {
			SliderCaptcha
			// Popup
		},
		data() {
			return {
				show: false,
			};
		},
	};
</script>


网站公告

今日签到

点亮在社区的每一天
去签到