前端防篡改水印

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

环境 :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...

相关推荐
清幽竹客31 分钟前
vue-37(模拟依赖项进行隔离测试)
前端·vue.js
vvilkim32 分钟前
Nuxt.js 页面与布局系统深度解析:构建高效 Vue 应用的关键
前端·javascript·vue.js
paopaokaka_luck34 分钟前
基于SpringBoot+Vue的电影售票系统(协同过滤算法)
vue.js·spring boot·后端
滿36 分钟前
Vue3 父子组件表单滚动到校验错误的位置实现方法
前端·javascript·vue.js
要加油哦~6 小时前
vue | 插件 | 移动文件的插件 —— move-file-cli 插件 的安装与使用
前端·javascript·vue.js
小林学习编程6 小时前
Springboot + vue + uni-app小程序web端全套家具商场
前端·vue.js·spring boot
影子信息10 小时前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月10 小时前
1.vue权衡的艺术
前端·vue.js·开源
RunsenLIu10 小时前
基于Vue.js + Node.js + MySQL实现的图书销售管理系统
vue.js·mysql·node.js
样子201810 小时前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript