uni-app + Spring Boot 实现 WiFi/蓝牙双因子考勤:设备配置、距离校验和打卡证据链
很多考勤系统一开始只做 GPS 定位结果上线后争议反而变多员工明明在公司系统提示“不在范围”办公楼里定位漂移主管说不清到底是不是误判门店和仓库只有几十米距离地图点位一偏就跨区。这类问题不能只靠“把定位半径调大”。半径一大误判少了但考勤可信度也下降。更稳的设计是把现场证据拆成多层GPS 解决“在哪个区域”WiFi 解决“连的是不是这个场所的网络”蓝牙解决“是不是靠近这个工位或设备点”。三类证据合在一起才更像一条能解释的考勤证据链。这篇文章基于智慧考勤项目真实代码做一次脱敏整理重点看 WiFi 和蓝牙设备如何参与打卡判断。真实项目素材主要来自后端 WiFi 实体zhkq-api/jeecg-module-zhkq/src/main/java/org/jeecg/modules/biz/entity/KqWifiConfig.java后端蓝牙实体KqBluetoothDevice.java打卡记录实体KqAttendanceRecord.javaWiFi 控制器KqWifiConfigController蓝牙控制器KqBluetoothDeviceControllerApp 打卡接口AppKqAttendanceRecordController移动端 WiFi 能力zhkq-uniapp/src/common/uniApi/wifi.js移动端蓝牙能力zhkq-uniapp/src/common/uniApi/bluetooth.jsPC 后台 APIzhkq-web/src/views/attendance/wifi/wifi.api.ts、attendance/bluetooth/blue.api.ts下面的 Demo 不是内部工程原文件全文复制而是按真实字段、接口风格和业务边界重新整理的一条最小闭环。它适合迁移到门店签到、仓库巡检、设备保养、项目现场、工单到场等系统。一、为什么 WiFi 和蓝牙要一起用真实项目里WiFi 配置表 kq_wifi_config 至少包含这些字段字段含义业务价值deviceName设备名称给后台和员工提示用避免只看到一串 MACdeviceMacBSSID/MAC用于识别真实接入点比 WiFi 名称更稳定longitude、latitude设备所在经纬度辅助判断设备位置是否和考勤点一致address位置描述便于后台维护和导出排查sysOrgCode所属组织做数据权限和多部门隔离蓝牙设备表 kq_bluetooth_device 多了几个近场识别字段字段含义业务价值deviceUuid蓝牙 UUID识别同一类 Beacon 或设备deviceCode设备唯一识别号用于去重和设备定位maiorNo、minorNomajor/minor 编号用于区分楼层、门店、工位或点位longitude、latitude部署位置辅助地图展示和距离判断deviceAddress设备位置描述解释“这个蓝牙点在哪里”WiFi 的特点是覆盖范围大适合判断“是否在公司、门店或厂区”。蓝牙的特点是覆盖范围小适合判断“是否靠近入口、考勤机、仓库门、设备点位”。两者组合后系统可以返回更清楚的失败原因不是简单说“打卡失败”而是告诉用户“未连接指定 WiFi”“未扫描到附近蓝牙设备”“定位距离偏差过大”。二、真实工程里已经做了哪些关键处理项目里的 WiFi 和蓝牙控制器不是简单 CRUD有两个值得保留的工程点。第一后台列表做了组织权限过滤。KqWifiConfigController 和 KqBluetoothDeviceController 都会通过当前用户能管理的部门列表过滤 sysOrgCode。这说明设备不是全局可见的同一个集团下不同门店、不同部门只能维护自己范围内的设备。第二新增和编辑时做了重复校验。WiFi 通过设备名称或 BSSID 去重蓝牙通过设备名称或 UUID 去重导入 Excel 时也会逐行校验必填字段和重复数据。这个细节很重要因为现场设备一旦重复后续打卡证据就会变得不可解释。移动端也不是直接读一个值就完事。wifi.js 里会先 uni.startWifi再 uni.getConnectedWifi 或 uni.getWifiList失败时会把 12005、12010 这类 WiFi 未开启错误转成可读提示。bluetooth.js 里会先打开蓝牙适配器再启动扫描最后读取设备列表并在 3 分钟后关闭扫描避免一直占用手机资源。这些都可以沉淀成一个公开 Demo。三、完整源码 Demo双因子打卡证据链1. EntityWiFi 配置package com.demo.attendance.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * WiFi 考勤设备配置。 * 业务边界只维护可用于现场识别的 WiFi 接入点不负责计算考勤结果。 */ Data TableName(demo_kq_wifi_config) public class WifiConfig { /** 主键 */ private String id; /** 后台可读设备名称 */ private String deviceName; /** WiFi BSSID/MAC实际匹配时优先使用 */ private String deviceMac; /** 部署经度 */ private String longitude; /** 部署纬度 */ private String latitude; /** 部署位置描述 */ private String address; /** 组织编码用于数据权限隔离 */ private String sysOrgCode; }2. Entity蓝牙设备package com.demo.attendance.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * 蓝牙考勤设备配置。 * 业务边界描述一个可被移动端扫描到的近场设备用于增强现场证据。 */ Data TableName(demo_kq_bluetooth_device) public class BluetoothDevice { private String id; private String deviceName; private String deviceUuid; private String deviceCode; private String majorNo; private String minorNo; private String longitude; private String latitude; private String deviceAddress; private String sysOrgCode; }3. DTO移动端提交的现场证据package com.demo.attendance.dto; import lombok.Data; import javax.validation.constraints.NotBlank; import java.time.LocalDateTime; import java.util.List; /** * 移动端打卡证据。 * 只承载手机采集到的现场数据最终是否有效由后端统一判断。 */ Data public class ClockEvidenceDTO { NotBlank(message 打卡类型不能为空) private String clockType; NotBlank(message 上下班类型不能为空) private String upDownWorkClock; private LocalDateTime clockTime; private String longitude; private String latitude; private String address; private String connectedWifiBssid; private String connectedWifiName; private ListScannedBluetoothDTO bluetoothDevices; private String clockImg; }package com.demo.attendance.dto; import lombok.Data; /** * 移动端扫描到的蓝牙设备。 */ Data public class ScannedBluetoothDTO { private String uuid; private String deviceId; private String major; private String minor; private Integer rssi; }4. VO返回给移动端的判断结果package com.demo.attendance.vo; import lombok.Data; /** * 打卡判断结果。 * 给移动端明确原因避免只返回“失败”导致员工和主管继续扯皮。 */ Data public class ClockEvidenceResultVO { private Boolean passed; private String message; private Boolean gpsPassed; private Boolean wifiPassed; private Boolean bluetoothPassed; private String matchedWifiName; private String matchedBluetoothName; }5. Mapperpackage com.demo.attendance.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.demo.attendance.entity.WifiConfig; public interface WifiConfigMapper extends BaseMapperWifiConfig { }package com.demo.attendance.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.demo.attendance.entity.BluetoothDevice; public interface BluetoothDeviceMapper extends BaseMapperBluetoothDevice { }6. Servicepackage com.demo.attendance.service; import com.demo.attendance.dto.ClockEvidenceDTO; import com.demo.attendance.vo.ClockEvidenceResultVO; /** * 考勤证据校验服务。 */ public interface ClockEvidenceService { /** * 校验移动端提交的 GPS、WiFi、蓝牙证据并返回可解释结果。 */ ClockEvidenceResultVO verify(ClockEvidenceDTO dto, String userId, String orgCode); }7. ServiceImpl核心判断package com.demo.attendance.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.demo.attendance.dto.ClockEvidenceDTO; import com.demo.attendance.dto.ScannedBluetoothDTO; import com.demo.attendance.entity.BluetoothDevice; import com.demo.attendance.entity.WifiConfig; import com.demo.attendance.mapper.BluetoothDeviceMapper; import com.demo.attendance.mapper.WifiConfigMapper; import com.demo.attendance.service.ClockEvidenceService; import com.demo.attendance.vo.ClockEvidenceResultVO; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.time.LocalDateTime; import java.util.List; import java.util.Objects; /** * WiFi/蓝牙双因子打卡证据校验。 * 这里不直接写死考勤状态只判断现场证据是否可信后续再交给考勤规则服务计算迟到、早退、缺卡等状态。 */ Service RequiredArgsConstructor public class ClockEvidenceServiceImpl implements ClockEvidenceService { private final WifiConfigMapper wifiConfigMapper; private final BluetoothDeviceMapper bluetoothDeviceMapper; Override public ClockEvidenceResultVO verify(ClockEvidenceDTO dto, String userId, String orgCode) { ClockEvidenceResultVO result new ClockEvidenceResultVO(); result.setGpsPassed(StringUtils.hasText(dto.getLongitude()) StringUtils.hasText(dto.getLatitude())); WifiConfig wifi matchWifi(dto.getConnectedWifiBssid(), orgCode); result.setWifiPassed(wifi ! null); result.setMatchedWifiName(wifi null ? null : wifi.getDeviceName()); BluetoothDevice bluetooth matchBluetooth(dto.getBluetoothDevices(), orgCode); result.setBluetoothPassed(bluetooth ! null); result.setMatchedBluetoothName(bluetooth null ? null : bluetooth.getDeviceName()); boolean passed Boolean.TRUE.equals(result.getGpsPassed()) (Boolean.TRUE.equals(result.getWifiPassed()) || Boolean.TRUE.equals(result.getBluetoothPassed())); result.setPassed(passed); result.setMessage(buildMessage(result)); return result; } private WifiConfig matchWifi(String bssid, String orgCode) { if (!StringUtils.hasText(bssid)) { return null; } return wifiConfigMapper.selectOne(new LambdaQueryWrapperWifiConfig() .eq(WifiConfig::getDeviceMac, bssid) .eq(WifiConfig::getSysOrgCode, orgCode) .last(limit 1)); } private BluetoothDevice matchBluetooth(ListScannedBluetoothDTO devices, String orgCode) { if (CollectionUtils.isEmpty(devices)) { return null; } for (ScannedBluetoothDTO item : devices) { BluetoothDevice device bluetoothDeviceMapper.selectOne(new LambdaQueryWrapperBluetoothDevice() .eq(StringUtils.hasText(item.getUuid()), BluetoothDevice::getDeviceUuid, item.getUuid()) .eq(StringUtils.hasText(item.getDeviceId()), BluetoothDevice::getDeviceCode, item.getDeviceId()) .eq(StringUtils.hasText(item.getMajor()), BluetoothDevice::getMajorNo, item.getMajor()) .eq(StringUtils.hasText(item.getMinor()), BluetoothDevice::getMinorNo, item.getMinor()) .eq(BluetoothDevice::getSysOrgCode, orgCode) .last(limit 1)); if (Objects.nonNull(device)) { return device; } } return null; } private String buildMessage(ClockEvidenceResultVO result) { if (!Boolean.TRUE.equals(result.getGpsPassed())) { return 未获取到定位信息请检查定位权限; } if (Boolean.TRUE.equals(result.getWifiPassed()) || Boolean.TRUE.equals(result.getBluetoothPassed())) { return 现场证据校验通过; } return 未匹配到允许打卡的 WiFi 或蓝牙设备; } }8. Controller移动端提交入口package com.demo.attendance.controller; import com.demo.attendance.dto.ClockEvidenceDTO; import com.demo.attendance.service.ClockEvidenceService; import com.demo.attendance.vo.ClockEvidenceResultVO; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; /** * 移动端打卡证据接口。 */ RestController RequiredArgsConstructor RequestMapping(/app/clockEvidence) public class ClockEvidenceController { private final ClockEvidenceService clockEvidenceService; PostMapping(/verify) public ClockEvidenceResultVO verify(RequestBody Valid ClockEvidenceDTO dto) { String userId demo-user; String orgCode demo-org; return clockEvidenceService.verify(dto, userId, orgCode); } }9. uni-app采集 WiFi 和蓝牙import { uniGetConnectedWifi } from /common/uniApi/wifi.js import { uniGetBluetoothDevices } from /common/uniApi/bluetooth.js import http from /common/http export async function submitClockEvidence(baseForm) { let wifi null let bluetooth [] try { const wifiResult await uniGetConnectedWifi() wifi wifiResult wifiResult.wifi } catch (e) { console.log(WiFi 采集失败, e.message || e) } try { const blueResult await uniGetBluetoothDevices() bluetooth blueResult.devices || [] } catch (e) { console.log(蓝牙采集失败, e.message || e) } return http.post(/app/clockEvidence/verify, { ...baseForm, connectedWifiBssid: wifi wifi.BSSID, connectedWifiName: wifi wifi.SSID, bluetoothDevices: bluetooth.map(item ({ uuid: item.advertisServiceUUIDs item.advertisServiceUUIDs[0], deviceId: item.deviceId, major: item.major, minor: item.minor, rssi: item.RSSI })) }) }四、这套设计真正解决了什么第一它让失败原因可解释。员工打卡失败时系统可以告诉他是定位权限没开还是没有连接指定 WiFi还是没有扫描到蓝牙设备。问题越具体人工沟通成本越低。第二它把移动端从“裁判”降级为“采集器”。手机端只负责采集现场证据后端负责校验证据和生成结果。这一点非常关键因为手机时间、网络状态、系统权限都不完全可信。第三它天然支持组织隔离。真实项目里设备配置带 sysOrgCode后台查询也会按当前用户可管理部门过滤。这样集团型企业、连锁门店、多项目现场都可以共用一套设备模型。第四它能保留审计空间。最终落到 KqAttendanceRecord 时仍然保留 clockTime、longitude、latitude、clockAddress、clockImg、clockStatus、afStatus 等字段。后续员工申诉、主管审批、HR 统计都有基础数据可查。五、落地时最容易踩的坑1. 不要只用 WiFi 名称判断。SSID 可以重复BSSID/MAC 更适合作为识别字段。2. 不要一直扫描蓝牙。移动端要像项目里的 bluetooth.js 一样在限定时间内开启和关闭扫描减少耗电和系统占用。3. 不要把定位失败直接算旷工。应该先返回明确失败原因让员工重新授权或补充说明。4. 不要让所有部门共享设备。设备必须绑定组织或门店否则跨部门考勤会乱。5. 不要忽略导入校验。批量导入设备时必须校验设备名称、MAC、UUID、唯一识别号否则后面排查成本非常高。6. 不要让移动端直接决定考勤状态。迟到、早退、缺卡应该由后端结合规则统一计算。六、生产级改造建议如果把上面的 Demo 用到真实生产环境还要补三类能力。第一类是索引和唯一约束。WiFi 配置表建议至少给 device_mac、sys_org_code 建联合索引蓝牙设备表建议给 device_uuid、device_code、sys_org_code 建索引。设备导入时虽然可以在 Java 层做重复校验但数据库层仍然要保底否则并发导入或多人同时维护设备时可能出现重复设备。第二类是打卡幂等。移动端弱网时经常会重复提交尤其是员工看到页面没反应会连续点几次。后端可以用 personId clockType upDownWorkClock 时间窗口 做幂等判断也可以让移动端生成一次打卡请求号。真实项目里的 AppKqAttendanceRecordController 已经能处理缓存打卡上传这类场景更需要把“重复提交”和“补传”区分开。第三类是审计和解释。现场证据最好不要只保存最终结果还要保存当时采集到的关键摘要匹配到哪个 WiFi、匹配到哪个蓝牙、定位是否成功、失败原因是什么。否则员工后续申诉时系统只能看到“失败”两个字仍然无法解释为什么失败。下面是一个简化的索引建议CREATE UNIQUE INDEX uk_wifi_org_mac ON demo_kq_wifi_config(sys_org_code, device_mac); CREATE UNIQUE INDEX uk_bluetooth_org_code ON demo_kq_bluetooth_device(sys_org_code, device_code); CREATE INDEX idx_clock_person_time ON demo_attendance_record(person_id, clock_time);再补一个幂等判断示例/** * 判断员工在短时间窗口内是否已经提交过同类型打卡。 */ public boolean existsRecentClock(String personId, String clockType, String upDownWorkClock, LocalDateTime clockTime) { LocalDateTime start clockTime.minusMinutes(3); LocalDateTime end clockTime.plusMinutes(3); Long count attendanceRecordMapper.selectCount(new LambdaQueryWrapperAttendanceRecord() .eq(AttendanceRecord::getPersonId, personId) .eq(AttendanceRecord::getClockType, clockType) .eq(AttendanceRecord::getUpDownWorkClock, upDownWorkClock) .between(AttendanceRecord::getClockTime, start, end)); return count ! null count 0; }这个判断不复杂但非常实用。没有幂等弱网补传会变成重复打卡没有审计异常申诉会变成聊天解释没有索引设备一多现场校验会拖慢移动端体验。七、可复用总结这套 WiFi 蓝牙证据链不只适合考勤。门店巡检可以用它判断员工是否真的到店仓库作业可以用它判断人员是否到达指定库区设备保养可以用蓝牙点位确认是否靠近设备物业巡更可以用 WiFi 和蓝牙减少虚假签到上门服务可以用多证据减少客户和服务人员之间的争议。企业系统真正有价值的地方不是多收集几个字段而是让每条记录未来都能解释。WiFi、蓝牙、GPS、照片、时间、组织权限、异常申诉连成一条链考勤记录才不只是“打了一次卡”而是一条能被员工、主管、HR 和老板共同理解的业务证据。

相关新闻

本地大模型端口暴露风险与Ollama/Dify/vLLM安全加固指南

本地大模型端口暴露风险与Ollama/Dify/vLLM安全加固指南

1. 项目概述:这不是漏洞预警,而是一次本地大模型安全意识的集体补课“我找到了上万个本地部署的DeepSeek大模型!”——这句话乍看像黑客炫耀战果,实则是一记响亮的警钟。它背后没有神秘exploit,没有0day漏洞&#xff0…

2026/7/7 3:20:30 阅读更多 →
mysql数据库服务器的启动方式(默认开机自启)

mysql数据库服务器的启动方式(默认开机自启)

方式一:可视化界面启动1.Win R 打开运行框2.输入:services.msc3.点击回车4.在打开的列表中下划找到mysql80 鼠标右键点击方式二:命令提示符启动1.在开始界面中搜索cmd 右键以管理员身份运行2.在终端窗口中输入:net start mysql80 3.关闭服务…

2026/7/7 3:18:30 阅读更多 →
5步彻底解决Visual C++运行库问题:VisualCppRedist AIO实用指南

5步彻底解决Visual C++运行库问题:VisualCppRedist AIO实用指南

5步彻底解决Visual C运行库问题:VisualCppRedist AIO实用指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 还在为"MSVCP140.dll缺失"、…

2026/7/7 3:16:30 阅读更多 →

最新新闻

Python API自动化测试框架:从设计原理到工程实践全解析

Python API自动化测试框架:从设计原理到工程实践全解析

1. 项目概述:为什么我们需要一个自己的API自动化框架?在软件开发和测试领域,API接口自动化测试早已不是新鲜事。市面上有Postman、JMeter、RestAssured等成熟工具,开源社区也有pytest-requests、httpx等优秀的库。那么&#xff0c…

2026/7/7 4:29:44 阅读更多 →
论软件测试方法及应用

论软件测试方法及应用

论软件测试方法及应用请围绕“论软件测试方法及应用”论题,依次从以下三个方面进行论述。1.概要叙述你参与管理和开发的软件项目以及你在其中所承担的主要工作。2.说明三种静态测试方法的概念,代码审查,静态结构分析和代码质量度量。3.结合项…

2026/7/7 4:27:44 阅读更多 →
别再死磕提示词了!2026年,做小红书图文带货,聪明人都在用这套“商品工作流

别再死磕提示词了!2026年,做小红书图文带货,聪明人都在用这套“商品工作流

最近跟几个做小红书图文带货的朋友聊天,大家普遍有一种很深的无力感。不是因为不够努力,相反,大家都很拼。天天在各种群里收藏最新的 AI 提示词,追着各种新工具跑,甚至连最近流行的“循环工程”都去研究了一遍。但回到…

2026/7/7 4:25:44 阅读更多 →
RT-Thread 内核对象管理机制剖析:从 rt_object 结构体看设计模式在 RTOS 中的落地

RT-Thread 内核对象管理机制剖析:从 rt_object 结构体看设计模式在 RTOS 中的落地

RT-Thread 内核对象管理机制剖析:从 rt_object 结构体看设计模式在 RTOS 中的落地 一、当内核对象的数据结构成为架构瓶颈 在 RTOS 的开发中,线程、信号量、互斥量、消息队列、定时器等内核对象是构建并发应用的基础。不同的 RTOS 对这些对象的管理方式差…

2026/7/7 4:21:43 阅读更多 →
数据中心存储系统故障了?怎么办!

数据中心存储系统故障了?怎么办!

存储系统是大数据与云计算的基础,其稳定性至关重要。以下是针对存储系统故障处置的简要思路总结。前置准备 处理故障前,需深入理解存储系统的架构与原理。典型存储系统由主机、交换机和存储设备组成,通过直连、IP网络或FC网络互联&#xff0c…

2026/7/7 4:19:42 阅读更多 →
ATT专利开放催生硅谷,AI时代公有智慧私有攫取引发法律与伦理争议!

ATT专利开放催生硅谷,AI时代公有智慧私有攫取引发法律与伦理争议!

公有智慧的私有攫取1956年1月24日,美国电话电报公司(AT&T)作为当时全球最大私营公司,营收占美国GDP近2%,有74.6万员工。旗下贝尔实验室成就卓越,为科学家赢得五项图灵奖和十项诺贝尔奖。当天AT&T签…

2026/7/7 4:17:42 阅读更多 →

日新闻

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

图片浏览是移动应用中最高频的场景之一。从社交应用的照片流到电商平台的商品图集,从旅游应用的景点相册到摄影作品展示——用户对图片浏览的体验要求不断提高:流畅的切换动画、直观的缩略图导航、便捷的收藏操作、自动播放模式。HarmonyOS NEXT ArkUI 虽…

2026/7/7 0:05:16 阅读更多 →
24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V稳压芯片完整选型指南 PW8600 PW75XX PW2815 PW2312B LDODC/DC全方案 一、24V稳压方案概述 24V直流电源在工业自动化、门禁系统、电梯控制、汽车电子、LED驱动、监控设备等场景中应用极广,是最常见的中压直流母线电压。要将24V母线稳定降压至下游MCU、传感器…

2026/7/7 0:05:16 阅读更多 →
RAG+知识图谱混合检索与Graph RAG核心对比

RAG+知识图谱混合检索与Graph RAG核心对比

做企业RAG落地的团队,往往容易卡在一容易踩坑的选型难题: 当需求单纯靠向量RAG搞不定、单纯靠知识图谱也搞不定,必须同时依赖「文本语义理解 实体关系推理」时,到底是做「向量图谱混合检索」就够了,还是必须上「Grap…

2026/7/7 0:07:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻