登录 - 腾讯云
在 人脸识别控制台 中,按照页面提示,同意《人脸识别服务规则》后,即可开通服务。
点击人员库名称进去创建人员
API Explorer - 云 API - 控制台
# 生成token包
npm i jsonwebtoken
# 腾讯人脸识别包
npm i tencentcloud-sdk-nodejs-iai
# 配置跨域包
npm i cors
别忘了在app中配置跨域
//生成token包(npm i jsonwebtoken)
let jwt = require("jsonwebtoken")
//腾讯人脸识别包(npm i tencentcloud-sdk-nodejs-iai)
const tencentcloud = require("tencentcloud-sdk-nodejs-iai");
//人脸识别登录
router.post('/faceLogin',async (req, res) => {
//获取前端传来的base64
let b64 = req.body.b64
const IaiClient = tencentcloud.iai.v20200303.Client;
const clientConfig = {
credential: {
//自己的腾讯secretId
secretId: "自己的腾讯secretId",
//自己的腾讯密匙
secretKey: "自己的腾讯密匙",
},
region: "ap-beijing", //地域参数(华北地区北京)
profile: {
httpProfile: {
endpoint: "iai.tencentcloudapi.com",
},
},
};
const client = new IaiClient(clientConfig);
const params = {
"GroupIds": [ //你创建的人员库ID
"你创建的人员库ID"
],
"Image": b64, //图片的base64格式编码
"NeedPersonInfo": 1, //是否返回人员具体信息。0 为关闭,1 为开启。默认为 0。
"QualityControl": 0, //图片质量控制。 0: 不进行控制; 1:较低的质量要求
"FaceMatchThreshold": 85, //人脸对比度设置为大于85才可
};
let doc = await client.SearchFaces(params)
//doc为人脸识别后的返回信息
console.log(doc,'doc');
if(doc.FaceNum===1){ //表示当前人脸库有该人员
let personId = doc.Results[0].Candidates[0].PersonId //拿到该人员的ID
let personName = doc.Results[0].Candidates[0].PersonName //拿到该人员的名称
console.log(personName,'personNume');
//根据该人员的名称去MongoDB中查询该用户对象(可以跳过这一步)
let userObj = await userModel.findOne({username:personName})
console.log(userObj,'userObj');
if (userObj) { //如果查询到该用户
//生成token
let token = jwt.sign({ "name": userObj.username }, "secretKey", { expiresIn: '1d' })
res.send({
code: 200,
msg: "登录成功!",
userObj,
token
})
return false
} else {
res.send({
code: 250,
msg: "用户名或密码错误!",
doc
})
return false
}
}else{
res.send({
code:251,
msg:'人脸库无此人!'
})
return false
}
})
后端工程配置完毕,如有疑问可自行百度,也可私信up
百度网盘下载js工具包
链接: https://pan.baidu.com/s/1snApbFqPPwOkhxwDWZ7_LA
提取码: dxc6
解压后会得到一个js文件夹,把它放到src/assets文件夹下
前端中用到了element-ui组件库,需提前配置好
<template>
<div class="login-wrapper">
<div class="big-box" v-show="isShowV">
<div class="video-box">
<video id="video" width="320" height="240" preload autoplay loop muted></video>
<canvas id="canvas" width="320" height="240"></canvas>
</div>
<div class="success-face">
<canvas id="screenshotCanvas" width="320" height="240"></canvas>
<div class="switch-button">
<el-row>
<el-button type="primary" @click="destroyed">关闭摄像头</el-button>
<el-button type="primary" @click="init">开始识别</el-button>
</el-row>
</div>
</div>
</div>
<div class="login-form">
<div class="title-container">
<div class="t_wel">欢迎登录</div>
<div class="t_site">小川数据可视化平台</div>
</div>
<div class="form-box">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" class="demo-ruleForm">
<el-form-item prop="username">
<el-input v-model="ruleForm.username" prefix-icon="el-icon-user-solid" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input show-password v-model="ruleForm.password" prefix-icon="el-icon-lock" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item>
<el-button @keyup.enter="keyDown" type="primary" @click="submitForm('ruleForm')" style="width: 100%;padding: 15px 0">立即登录</el-button>
</el-form-item>
<el-form-item>
<el-button type="text" @click="faceLoginBtn">人脸识别登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import tracking from '@/assets/js/tracking-min'
import '@/assets/js/face-min.js'
export default {
name: "Login2",
data() {
return {
ruleForm: {
username: 'admin',
password: '123',
},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
],
},
//人脸识别用到的变量
trackerTask: null,
mediaStreamTrack: null,
video: null,
screenshotCanvas: null,
uploadLock: true, // 上传锁
isShowV:false
};
},
methods: {
//人脸识别登录
faceLoginBtn(){
this.isShowV = this
this.init();
},
// 初始化设置
init() {
this.video = this.mediaStreamTrack = document.getElementById('video');
this.screenshotCanvas = document.getElementById('screenshotCanvas');
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
// 固定写法
let tracker = new window.tracking.ObjectTracker('face');
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);
//摄像头初始化
this.trackerTask = window.tracking.track('#video', tracker, {
camera: true
});
let _this = this;
//监听图像变化
tracker.on('track', function(event) {
// 检测出人脸 绘画人脸位置
context.clearRect(0, 0, canvas.width, canvas.height);
event.data.forEach(function(rect) {
context.strokeStyle = '#76e535';
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
});
// event.data.length长度为多少代表检测几张人脸
if(_this.uploadLock && event.data.length){
//上传图片
_this.screenshotAndUpload();
}
});
},
// 上传图片
screenshotAndUpload() {
// 上锁避免重复发送请求
this.uploadLock = false;
// 绘制当前帧图片转换为base64格式
let canvas = this.screenshotCanvas;
let video = this.video;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
//base64Img为最终人像数据
let base64Img = canvas.toDataURL('image/jpeg');
//发送给后端
this.$http.post("http://localhost:3000/users/faceLogin",{b64:base64Img.split(',')[1]}).then(res=>{
if(res.data.code===200){
//登录成功把token存在浏览器会话存储中
sessionStorage.setItem("token",res.data.token)
this.$message.success(res.data.msg)
this.destroyed();
}else if(res.data.code===250){
console.log(res.data,'res.data')
this.$message.error(res.data.msg)
this.destroyed();
}else if(res.data.code===251){
console.log(res.data,'res.data')
this.$message.error(res.data.msg)
this.destroyed();
}
})
// 请求接口成功以后打开锁
// this.uploadLock = true;
},
//关闭摄像头
destroyed(){
if(!this.mediaStreamTrack){
return
}
this.mediaStreamTrack.srcObject.getTracks()[0].stop();
this.trackerTask.stop()
this.isShowV = false
},
//键盘事件
keyDown(e){
//如果是回车则执行登录方法
if(e.keyCode === 13){
//需要执行的登录方法
this.submitForm('ruleForm');
}
},
//表单登录按钮
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$message.success('本登录只能使用人脸登录!')
} else {
console.log('error submit!!');
this.$message.error('请填写登录信息!!!')
return false;
}
});
},
},
mounted() {
//绑定事件
window.addEventListener('keydown',this.keyDown);
},
//销毁事件
destroyed(){
window.removeEventListener('keydown',this.keyDown,false);
}
}
</script>
<style lang="scss" scoped>
html,body{
width: 100%;
height: 100%;
}
*{
box-sizing: border-box;
}
.login-wrapper{
//background-image: url("@/assets/image/暗系-风景.png") ;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: center center;
overflow: hidden;
.login-form{
position: absolute;
left: 80%;
top: 50%;
-webkit-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
width: 480px;
height: 465px;
max-width: 100%;
margin-right: 120px;
padding: 40px 70px 0;
overflow: hidden;
background-color: rgba(255,255,255,.1);
border-radius: 15px;
.title-container{
position: relative;
text-align: center;
.t_wel{
font-size: 26px;
line-height: 1;
color: #eee;
margin-bottom: 10px;
}
.t_site{
font-size: 14px;
line-height: 1;
color: #bebebe;
margin-bottom: 26px;
}
}
.form-box{
.el-form{
.el-form-item{
.el-input{
margin-top: 10px;
}
.el-button{
margin-top: 10px;
}
}
}
}
}
.big-box{
position: absolute;
top: 5%;
left: 50%;
width: 320px;
//border: 1px solid #ddd;
//height: 700px;
transform: translate(-50%);
.video-box{
width: 320px;
height: 240px;
#canvas{
position: absolute;
top: 0;
left: 0;
}
}
.success-face{
width: 320px;
height: 240px;
//border: #ddd solid 1px;
}
}
}
</style>
说明:不管前端怎么写,只要能生成图片的base64编码就行,只要往后端提交图片的base64格式编码即可
注意:前端项目启动只能在本地localhost访问,不能使用ip地址访问项目,不然浏览器调摄像头时会报错,原因是安全隐私问题。切记
前端登录效果图:
前端工程已完毕,如有疑问可自行百度,或者私信up