web人脸登录
1,需要腾讯人脸第三方
腾讯人脸第三方申请步骤
2,相关表结构设计
create database faceDB;use faceDB;
-- 人脸表
create table face(
fid int primary key auto_increment COMMENT '主键',
face_base longtext COMMENT '图片数据 base_64编码',
create_time datetime COMMENT '插入时间',
vef_num int COMMENT '验证次数',
face_name varchar(100) COMMENT '人脸名称',
remark varchar(200) COMMENT '人脸备注',
face_status int COMMENT '人脸是否可用,(0==可用,1,不可用)',
update_extend1 varchar(300) COMMENT '扩展字段1',
update_extend2 varchar(300) COMMENT '扩展字段2',
update_extend3 varchar(300) COMMENT '扩展字段3'
);
-- 验证日志表
create table face_vef_log(
lid int primary key auto_increment COMMENT '主键',
vef_time datetime COMMENT '验证时间',
vef_code int COMMENT '返回code',
vef_msg varchar(200) COMMENT '返回的消息',
login_name varchar(100) COMMENT '验证人'
);
3,相关配置
tencentcloudapi:# 你的 secretIdsecretId: 你腾讯云的secretId# 你的 secretKeysecretKey: 你腾讯云的secretKey# 请求官方地址 不变endpoint: iai.tencentcloudapi.com#地域 可不变region: ap-shanghai
package com.face.config;import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.face.utils.JwtUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;/*** @author tanyongpeng* <p>des</p>**/
@Component
@Slf4j
public class FaceConfig implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String face_token = request.getHeader("face_token");Map<String,Object> infoMap = new HashMap<>();try{//token验证DecodedJWT tokenInfo = JwtUtils.getTokenInfo(face_token);//添加返回信息infoMap.put("msg","验证成功");return true;}catch (SignatureVerificationException e){e.printStackTrace();infoMap.put("msg","无效签名");}catch (TokenExpiredException e){infoMap.put("msg","token已过期");}catch (AlgorithmMismatchException e){infoMap.put("msg","算法不一致");}catch (Exception e){infoMap.put("msg","无效签名");}ObjectMapper objectMapper = new ObjectMapper();String mapInfoJson = objectMapper.writeValueAsString(infoMap);response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");PrintWriter writer = response.getWriter();writer.write(mapInfoJson);return false;}
}
package com.face.server;import com.face.bean.result.FaceResult;
import com.face.utils.TimeUtils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iai.v20180301.IaiClient;
import com.tencentcloudapi.iai.v20180301.models.CompareFaceRequest;
import com.tencentcloudapi.iai.v20180301.models.CompareFaceResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;/*** @author tanyongpeng* <p>调用腾讯接口</p>**/
@Component
@Data
@Slf4j
public class FaceContrastServer {@Value("${tencentcloudapi.secretId}")private String secretId;@Value("${tencentcloudapi.secretKey}")private String secretKey;@Value("${tencentcloudapi.endpoint}")private String endpoint;@Value("${tencentcloudapi.region}")private String region;//第一张是数据库图片,第二张是登录时验证图片public FaceResult faceContrast(String imageA, String imageB){FaceResult faceResult = new FaceResult();try{Credential cred = new Credential(secretId, secretKey);HttpProfile httpProfile = new HttpProfile();httpProfile.setEndpoint(endpoint);ClientProfile clientProfile = new ClientProfile();clientProfile.setHttpProfile(httpProfile);IaiClient client = new IaiClient(cred, region, clientProfile);CompareFaceRequest req = new CompareFaceRequest();req.setImageA(imageA);req.setImageB(imageB);CompareFaceResponse resp = client.CompareFace(req);faceResult.setScore(resp.getScore());faceResult.setCode(FaceResult.SUCCESS_CODE);} catch (TencentCloudSDKException e) {faceResult.setCode(FaceResult.FACE_ERROR);faceResult.setMsg(e.getMessage());}return faceResult;}
}
4,人脸注册,登录后端代码
package com.face.service.impl;import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.face.bean.Face;
import com.face.bean.result.FaceResult;
import com.face.mapper.FaceMapper;
import com.face.server.FaceContrastServer;
import com.face.service.FaceService;
import com.face.utils.JwtUtils;
import com.face.utils.TimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/**
* @author typsusan
* @description 针对表【face】的数据库操作Service实现
* @createDate 2022-07-17 03:33:50
*/
@Service
public class FaceServiceImpl extends ServiceImpl<FaceMapper, Face>implements FaceService {@AutowiredFaceContrastServer faceContrastServer;@Overridepublic FaceResult vef(String imageBase) {imageBase = JSONUtil.parseObj(imageBase).getStr("imageBase");List<Face> faceList = lambdaQuery().orderByDesc(Face::getVefNum).list();FaceResult faceState = null;// 如果人脸库为空,则第一次登录为录入人脸if (faceList.size() == 0){return initFace(imageBase);}else {int faceLength = faceList.size();for (Face face : faceList) {FaceResult faceResult = faceContrastServer.faceContrast(face.getFaceBase(), imageBase);// 是否比对成功if (faceResult.getCode() == FaceResult.SUCCESS_CODE ){// 相似度是否大于80if (faceResult.getScore() > FaceResult.SATISFY_SCORE){if (face.getFaceStatus() == 0){// 成功lambdaUpdate().set(Face::getVefNum,face.getVefNum()+1).eq(Face::getFid,face.getFid()).update();faceResult.setMsg(TimeUtils.timeQuantum()+"好,"+face.getFaceName());faceResult.setName(face.getFaceName());Map<String,String> map = new HashMap<>();map.put("score",String.valueOf(faceResult.getScore()));map.put("faceName",faceResult.getName());faceResult.setToken(JwtUtils.genereteToken(map));return faceResult;}else {// 失败 人脸被禁用lambdaUpdate().set(Face::getVefNum,face.getVefNum()+1).eq(Face::getFid,face.getFid()).update();faceResult.setMsg(face.getFaceName()+",当前人脸被禁用");faceResult.setName(face.getFaceName());faceResult.setCode(FaceResult.FORBIDDEN_FACE);faceState = faceResult;// 就算上一张人脸被禁用还得往下执行// 可能当前用户存在多张人脸,if (faceLength == 1){return faceResult;}faceLength --;}}else {// 人脸库没有检测到人脸if (faceLength == 1){// 判断当前人脸是否被禁用,如被禁用,提示被禁用// 禁用优先级大于 没有检测到人脸return faceState != null?faceState:FaceResult.error(FaceResult.NOT_FOUND_FACE,"人脸库不存在该人脸",faceResult.getScore());}faceLength --;}}else {// 接口返回异常return faceResult;}}}// 空异常return FaceResult.error(FaceResult.NULL_ERROR,"空指针异常");}public FaceResult initFace(String imageBase){FaceResult faceResult = new FaceResult();Face face = new Face();face.setFaceBase(imageBase);face.setCreateTime(new Date());face.setVefNum(0);face.setFaceName("admin");face.setFaceStatus(0);boolean save = save(face);faceResult.setCode(FaceResult.INIT_FACE);faceResult.setMsg("人脸初始化"+(save?"成功":"失败")+","+(save?"请验证登录":"请稍后再试"));faceResult.setName(face.getFaceName());return faceResult;}
}
5,前端代码
/*** 获取 浏览器 拍照的权限*/
/*** 获取浏览器权限* @param option*/
function getCamera(option) {option.thisCancas = document.getElementById(option.canvasId);option.thisContext = option.thisCancas.getContext("2d");option.thisVideo = document.getElementById(option.videoId);option.thisVideo.style.display = "block";// 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象if (navigator.mediaDevices === undefined) {navigator.mediaDevices = {};}// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象// 使用getUserMedia,因为它会覆盖现有的属性。// 这里,如果缺少getUserMedia属性,就添加它。if (navigator.mediaDevices.getUserMedia === undefined) {navigator.mediaDevices.getUserMedia = function (constraints) {// 首先获取现存的getUserMedia(如果存在)var getUserMedia =navigator.webkitGetUserMedia ||navigator.mozGetUserMedia ||navigator.getUserMedia;// 有些浏览器不支持,会返回错误信息// 保持接口一致if (!getUserMedia) {//不存在则报错return Promise.reject(new Error("getUserMedia is not implemented in this browser"));}// 否则,使用Promise将调用包装到旧的navigator.getUserMediareturn new Promise(function (resolve, reject) {getUserMedia.call(navigator, constraints, resolve, reject);});};}var constraints = {audio: false,video: {width: option.videoWidth,height: option.videoHeight,transform: "scaleX(-1)",},};navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {// 旧的浏览器可能没有srcObjectif ("srcObject" in option.thisVideo) {option.thisVideo.srcObject = stream;} else {// 避免在新的浏览器中使用它,因为它正在被弃用。option.thisVideo.src = window.URL.createObjectURL(stream);}option.thisVideo.onloadedmetadata = function (e) {option.thisVideo.play();};}).catch((err) => {console.log(err);});return option
}/*** 绘制图片* 返回格式为base64* @param option*/
function draw(option){option.thisContext.drawImage(option.thisVideo,0,0,option.videoWidth,option.videoHeight);return option.thisCancas.toDataURL("image/png");
}export default {getCamera,draw
}
<template><div><div class="login"></div><!--登录中间块--><div class="login-mid"><div class="login-mid-top"><div class="shadow-top-left"></div><div class="shadow-top-right"></div></div><div class="login-mid-mid"><!--捕获人脸区域--><div class="videoCamera-canvasCamera"><videoid="videoCamera":width="videoWidth":height="videoHeight"autoplay></video><canvasstyle="display: none"id="canvasCamera":width="videoWidth":height="videoHeight"></canvas><!--人脸特效区域--><div v-if="faceImgState" class="face-special-effects-2"></div><div v-else class="face-special-effects"></div></div><!--按钮区域--><div class="face-btn"><button @click="faceVef()">{{faceImgState?'正在识别中...':'开始识别'}}</button></div><!--消息区域--><div class="msg"><div class="server-msg">{{msg}}</div><div class="welcome">Welcome to face recognition</div></div></div><div class="login-mid-bot"><div class="shadow-bot-left"></div><div class="shadow-bot-right"></div></div></div></div></template>
<script>
import $camera from '../../camera/index.js'
export default {data() {return {videoWidth: 200,videoHeight: 200,msg:'',faceImgState:false,faceOption:{}};},mounted() {//调用摄像头this.faceOption = $camera.getCamera({videoWidth: 200,videoHeight: 200,thisCancas: null,thisContext: null,thisVideo: null,canvasId:'canvasCamera',videoId:'videoCamera'});//this.getCompetence();},methods: {// 调用后台接口faceVef(){// 开始绘制图片let imageBase = $camera.draw(this.faceOption)if (this.faceImgState){return}this.faceImgState = trueif (imageBase === '' || imageBase === null || imageBase === undefined){this.$message.error("图片数据为空")}else {this.$http.post("/face/vef",{imageBase}).then(res =>{console.log(res)this.faceImgState = false// 跳转首页if (res.data.code === 200){// 关闭摄像头this.faceOption.thisVideo.srcObject.getTracks()[0].stop();localStorage.setItem("face_token",res.data.token);localStorage.setItem("username",res.data.name);this.$message.success(res.data.msg)this.$router.push("/home")}if (res.data.code === 201){this.$message.success(res.data.msg)}},onerror =>{this.faceImgState = false})}}},
};
</script>
<style>
@import "./index.css";
</style>
6,实现实例
参考:项目后端地址face-easy
参考:项目前端地址face-ui
相关文章:
web人脸登录
1,需要腾讯人脸第三方 腾讯人脸第三方申请步骤 2,相关表结构设计 create database faceDB;use faceDB; -- 人脸表 create table face( fid int primary key auto_increment COMMENT 主键, face_base longtext COMMENT 图片数据 base_64编码, create_tim…...
C++数字
目录 一、什么是数字 二、定义数字 三、数学运算 四、随机数 一、什么是数字 通常,当我们需要用到数字时,我们会使用原始的数据类型,如 int、short、long、float 和 double 等等。这些用于数字的数据类型,其可能的值和数值范围…...
【python】用plotly绘制正二十面体
文章目录顶点棱实现正二十面体plotly 的 Python 软件包是一个开源的代码库,它基于 plot.js,而后者基于 d3.js。我们实际使用的则是一个对 plotly 进行封装的库,名叫 cufflinks,能让你更方便地使用 plotly 和 Pandas 数据表协同工作…...
[Datawhale][CS224W]图机器学习(五)
这里写目录标题一、Deepwalk1.1 预备知识1.2 Deepwalk介绍1.3 Embedding1.4 word2Vec 词向量,词嵌入1.5 random Walk随机游走1.6 DeepWalk 核心代码Random WalkWord2vecDeepWalk应用1.7 DeepWalk优缺点二、Node2Vec2.1 图嵌入2.2 Node2Vec优化目标顶点序列采样策略2…...
Windows部署Jar包的三种方式
文章目录1、cmd命令启动2、bat脚本启动2.1 启动jar包2.2 关闭服务3、使用WinSW3.1 重命名3.2 xml配置3.3 安装服务3.4 卸载服务3.5 启动和停止服务1、cmd命令启动 这种方式比较简单,但是窗口关闭后服务也就被杀死了,命令如下 java -jar xxx.jar2、bat脚…...
【图像分类】卷积神经网络之AlexNet网络模型结构详解
写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 1. 前言 LeNet5网络模型提出之后,卷积神经网络在很长一段时间都没有长足的发展,主要有以下两个原因: 1.1 训…...
学习动漫插画的网络班排行榜
很多小伙伴不知道动漫插画培训机构哪个好,找不到靠谱的插画班,今天给大家整理了国内动漫插画培训机构排名! 一:动漫插画培训机构排名 1、轻微课(五颗星) 主打课程有日系插画、游戏原画、古风插画、动漫漫画…...
SpringCloud第五讲 Nacos注册中心-服务注册到Nacos
1.引入依赖: 在父工程中添加spring-cloud-alibaba的管理依赖 <!-- Nacos的管理依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version…...
IP地理位置定位技术原理是什么
IP地理位置定位技术的原理是基于IP地址的网络通信原理和基础上的。它利用IP地址所包含的一些信息,如网络前缀和地址段,以及ISP的IP地址归属地数据库,来推测IP地址所对应的地理位置。具体来说,IP地址是由32位二进制数字组成的&…...
j-vxe-table 下拉搜索选择框数据加载过多导致前端崩溃问题
Jeeg-boot j-vxe-table 下拉搜索选择框数据加载过多导致前端崩溃问题 最近用到了Jeeg-boot j-vxe-table的组件,这组件时真J8难用,还好多BUG,想用个slot插槽也用不了,好像官方写了个基础就没怎么管了。😑 问题…...
Java国际化ResourceBundle详解
在Java开发中,ResourceBundle是一种方便地管理本地化资源的机制。它可以使得程序能够根据当前系统环境的语言和国家/地区来自动加载相应的本地化资源文件,从而避免了硬编码和减少了重复的代码。以下是使用ResourceBundle的基本步骤: 1. 准备…...
一文高端Android性能优化-总结篇
以下从几个方面来总结一下Android的性能优化:1:界面卡顿优化2:内存优化3:App启动优化界面卡顿优化Android的界面为每秒60帧,即必须在16ms内完成1帧的绘制,如果某个方法耗时过程,导致16ms内无法完…...
深入讲解CFS组调度!(上)
注:本文缩写说明 一、CFS组调度简介 1.1. 存在的原因 总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢,比如多用户计算机系统每个用户的所有任务划分到一个分组中,A用户90个相同任务,而B…...
大数据实操项目分享:餐饮智能推荐服务在线实习项目
项目背景:在“互联网"背景下,餐饮企业的经营方式发生了很大的变革:团购和020拓宽了销售 渠道,电子点餐、店内WIFI等信息技术提升了服务水平,大数据、私人定制更好地满足了细分市场的需求等。但是与此同时…...
代码随想录day38
动态规划五部曲 确定dp数组以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 509. 斐波那契数 https://leetcode.cn/problems/fibonacci-number/ class Solution {public int fib(int n) {if(n0) return 0;if(n<3) return 1;int[] dp new int[n]…...
《计算机网络:自顶向下方法》实验5:TCP
Q1 包含HTTP POST消息的TCP报文段的序号是多少?注意:为了发现POST 命令, 你需要在wireshark底部的报文内容域窗口中去查找,查找数据中包含 “POST”的段。 如图所示,由报文中的POST 和 HTTP/1.1可知,其包含HTTP POST消息; TCP报文段的序号可见TCP报文: Sequence Number:…...
【踩坑指南】Stable Diffusion 服务器端部署笔记
文章目录下载github文件配置环境ckpt文件权重下载生成图像NSFW检查(瑟图过滤)下载github文件 https://github.com/CompVis/stable-diffusion 这个网址,下载压缩包解压,也可以用git clone下载 配置环境 这一步坑最多,…...
[qiankun]-多页签缓存
[qiankun]-多页签缓存环境功能需求多页签缓存方案方案1.主服务进行html替换方案2.微服务vnode 替换方案3.每个微服务都不卸载微服务加载方式的选择微服务的路由路径选择微服务的缓存工具微服务的容器使用tab作为微服务的挂载容器使用微服务路由作为微服务的挂载容器场景描述微服…...
2|电子技术|数字电子技术基础|雨课堂习题|考前回顾
A/DD/A转化横向与阵列 相乘,竖向为或阵列 相加!功率放大电路克服交越失真,是在乙类的基础上增加两个二极管,使微导通,使三极管导通时间大于半个周期,小于一个周期,构成甲乙类工作状态。选择填空…...
vue+echarts:圆形柱状图设置角度和最大值
第020个点击查看专栏目录本示例是显示圆形的柱状图,angleAxis设置一个max, angleAxis上startAngle:90 , 将0点设置为最顶点。 文章目录示例效果示例源代码(共100行)相关资料参考专栏介绍示例效果 示例源代码…...
Godot PCK解包原理与专业逆向实践指南
1. 这不是“解压软件”,而是Godot游戏逆向工程的第一把手术刀你刚下载了一款用Godot引擎开发的独立游戏,想研究它的UI动效逻辑,或者复刻一段粒子特效,又或者只是单纯好奇——那个让你反复通关三次的像素风过场动画,图层…...
【DeepSeek-R1代码相似度引擎解密】:3层语义比对机制、Token归一化偏差修正与Jaccard阈值黄金分割点
更多请点击: https://kaifayun.com 第一章:DeepSeek代码重复检测 DeepSeek-R1 模型在训练过程中引入了严格的代码去重机制,其核心目标是消除训练语料中语义等价或高度相似的代码片段,从而提升模型对真实编程模式的学习能力与泛化…...
癫痫手术精准定位:基于脑电信号昼夜节律与多生物标志物的机器学习分析框架
1. 项目概述:当机器学习遇见脑电信号,如何让癫痫手术更精准?作为一名长期耕耘在生物医学信号处理与机器学习交叉领域的工程师,我常常思考如何将算法模型从实验室的“玩具”变成临床医生手中可靠的“手术刀”。癫痫,这个…...
用STM32CubeMX和HAL库快速上手WS2812B:告别手动计算延时,一键生成驱动框架
基于STM32CubeMX的WS2812B智能灯光控制:从零构建现代化驱动方案在智能硬件和物联网设备快速发展的今天,WS2812B可编程LED灯带因其丰富的色彩表现和简单的单线控制方式,成为创客和工程师们最喜爱的显示组件之一。然而,传统的寄存器…...
别再死记硬背Payload了!我用XSS-Game靶场,带你拆解18种过滤规则背后的绕过逻辑
从XSS-Game靶场实战中掌握18种过滤规则的逆向思维在网络安全领域,跨站脚本攻击(XSS)始终是Web应用面临的主要威胁之一。许多开发者虽然了解XSS的基本概念,但当面对各种复杂的过滤规则时,往往不知如何系统分析并构造有效…...
基于ATmega2560与ISD1700的智能语音时钟:硬件选型、软件架构与避坑指南
1. 项目概述与核心价值去年折腾那个用ATMega328驱动三块显示屏的时钟时,我主要精力都花在了如何在320x240的TFT屏幕上把时间、日期和图标画得又准又好看上。项目在《Elektor》杂志上发表后,一位热心的读者给我提了个新想法:能不能做个会“说话…...
告别数据饥荒:用PyTorch手把手实现原型网络(Prototypical Networks)做电影评论情感分类
告别数据饥荒:用PyTorch手把手实现原型网络做电影评论情感分类 在自然语言处理领域,情感分析一直是热门研究方向,但现实中的开发者常面临一个尴尬困境:标注数据太少。传统深度学习方法动辄需要成千上万的标注样本,而实…...
从RD、CS到WK:一文讲透SAR主流成像算法的演进与选型实战
从RD、CS到WK:SAR成像算法选型实战指南 当无人机掠过灾区上空,或卫星扫描地球表面时,合成孔径雷达(SAR)正通过电磁波穿透云层和黑暗,将地面信息转化为高分辨率图像。而决定图像质量的关键,在于工…...
【与我学 ClaudeCode】协作篇 之 Worktree + Task Isolation :目录隔离的并行执行通道
作者:逆境不可逃 技术永无止境 希望我的内容可以帮助到你!!!! 大家吼 ! 我是 逆境不可逃 今天给大家带来文章《【与我学 ClaudeCode】协作篇 之 Worktree Task Isolation :目录隔离的并行执行通道》. Le…...
武汉国电华美串联谐振试验装置,现场用着心里有底
在高压试验现场干了这么多年,这位老师傅常说,一台好的串联谐振装置,就是试验人员的胆。面对GIS、大型变压器、超高压电缆这些大电容试品,没有趁手的谐振设备,交流耐压试验根本没法干。16875kVA/225kV这个规格ÿ…...
