前端防篡改水印

本文将介绍一种前端防篡改的水印实现方式(防君子不防小人)

环境 :vite,vue3,node 18.20.8

一、实现水印

使用canvas画布实现一个水印背景图useWatermarkBg,该水印接收三个参数text:水印文字,fontSize:字体大小,gap: 字体间距

vue 复制代码
import { computed } from "vue";
export default function useWatermarkBg(props) {
    return computed(() => {
        const canvas = document.createElement("canvas");
        // 显示倍率
        const dpr = window.devicePixelRatio || 1;
        const fontSize = props.fontSize * dpr;
        const font = fontSize + "px serif";
        // 画板对象
        const ctx = canvas.getContext("2d");
        // 获取文字的宽度
        ctx.font = font;
        const { width } = ctx.measureText(props.text);
        const canvasSize = Math.max(100, width) + props.gap * dpr;
        // 设置画板大小
        canvas.width = canvasSize;
        canvas.height = canvasSize;
        ctx.translate(canvas.width / 2, canvas.height / 2);
        ctx.rotate((Math.PI / 180) * -45); // 倒序旋转-45°
        ctx.fillStyle = "rgba(0,0,0,0.3)";
        ctx.font = font;
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(props.text, 0, 0);
        return {
            base64: canvas.toDataURL(),
            size: canvasSize,
            styleSize: canvasSize / dpr,
        };
    });
};

二、实现水印的防篡改

使用MutationObserver监听需要添加水印的元素,在水印被删除或者修改时重新插入水印元素,实现水印的防篡改功能,具体实现代码如下:

vue 复制代码
<template>
  <div class="watermark-container" ref="parentRef">
    <slot></slot>
  </div>
</template>

<script setup>
import useWatermarkBg from "./useWatermarkBg";
import { ref, onMounted, onUnmounted } from "vue";
const props = defineProps({
  text: {
    type: String,
    required: true,
    default: "watermark",
  },
  fontSize: {
    type: Number,
    default: 40,
  },
  gap: {
    type: Number,
    default: 20,
  },
});
const parentRef = ref(null);
const bg = useWatermarkBg(props);
let div;
// 重置水印
const resetWatermark = () => {
  if (!parentRef.value) return;
  if (div) {
    div.remove();
  }
  const { base64, size } = bg.value;
  div = document.createElement("div");
  div.style.position = "absolute";
  div.style.backgroundImage = `url(${base64})`;
  div.style.backgroundSize = `${size}px ${size}px`;
  div.style.backgroundRepeat = "repeat";
  div.style.zIndex = 9999;
  div.style.inset = 0;
  div.style.pointerEvents = "none";
  parentRef.value.appendChild(div);
};
const ob = new MutationObserver((entries) => {
  for (const entry of entries) {
    // 处理div被删除的情况
    for (const node of entry.removedNodes) {
      if (node === div) {
        resetWatermark();
        return;
      }
    }
    // 处理div被修改的情况
    if (entry.target === div) {
      resetWatermark();
    }
  }
});
onMounted(() => {
  resetWatermark();
  // 监听parentRef的修改
  ob.observe(parentRef.value, {
    childList: true, //子元素
    subtree: true, //子树
    attributes: true, //属性
  });
});
onUnmounted(() => {
  ob.disconnect();
});
</script>

<style scoped>
.watermark-container {
  position: relative;
}
</style>

三、水印使用

vue 复制代码
<script setup>
import Watermark from "./components/Watermark.vue";
</script>

<template>
  <Watermark text="前端防篡改水印" style="background-color: beige">
    <div class="content"></div>
  </Watermark>
</template>

<style scoped>
.content {
  width: 100vw;
  height: 100vh;
}
</style>

附上完整代码地址:gitee.com/TriF/tamper...

相关推荐
Bee.Bee.7 分钟前
vue3提供的hook和通常的函数有什么区别
前端·javascript·vue.js
Nano16 分钟前
Vue响应式系统的进化:从Vue2到Vue3.X的深度解析
前端·vue.js
某人的小眼睛22 分钟前
vue3 element-plus 大文件切片上传
前端·vue.js
来自星星的猫教授31 分钟前
Vue 3.6前瞻:响应式性能革命与Vapor模式展望
前端·javascript·vue.js
用户3802258598241 小时前
Vue3源码解析:深度解读ref实现源码
vue.js
Chuck1sn1 小时前
我把 Cursor AI 整合到 Ruoyi 中,从此让 Java 脚手架脱离人工!
java·vue.js·后端
一只叫煤球的猫1 小时前
1200行代码的前端组件?这套拆分套路让代码从此优雅
前端·vue.js·性能优化
武昌库里写JAVA2 小时前
IDE(集成开发环境),集成阿里云的通义大模型
vue.js·spring boot·毕业设计·layui·课程设计
前端大卫2 小时前
localStorage 也能监听变化?带你实现组件和标签页的同步更新!【附完整 Vue/React Hook 源码】
前端·vue.js·react.js