Face-Server 实现人脸登录,人脸追踪,眨眨眼,摇摇头,张张嘴
官方文档
目前已经开源,点击下方连接跳转
https://faceeffet.com/
效果预览
人脸登录效果
前言
Face-server 是一款独立的人脸识别服务,通过API实现快速人脸登录,无需改动现有代码。主打功能包括人脸验证、追踪、消失与出现检测及活体验证。一键启动本地服务器,支持Windows和Linux部署,体积小功能强大。完全开源免费,提供后台配置服务,便于个性化设置人脸登录参数。适合各类项目,简化人脸登录流程,提升用户体验和安全性。
提示:以下是本篇文章正文内容,下面案例可供参考
一、效果预览
人脸登录效果
二、下载地址
百度网盘链接:
点击跳转
提取码: 8888
CSDN链接:
点击跳转
三、启用步骤
1.先解压,然后看见这3个文件
linux则运行.sh
windows 则运行windows.cmd
2.运行前准备
windows 已管理员模式运行
linux 运行前 则给当前文件设置权限
chmod 777 Linux - Mac启动.sh
’ Linux - Mac启动.sh ’ 这是整个文件名称,中间带有空格,为了引起不必要的麻烦,可以把sh脚本名称改一下
运行
./Linux - Mac启动.sh
3.启动成功
如果在linux或者windows执行报错
则在控制台执行以下命令
java -javaagent:face.jar -jar face.jar
上面两个脚本只是为了杀死当前重复的端口号
四、页面展示
1.启动成功后
浏览器输入:http://localhost:8999/face-server
2.配置中心
后端回调地址,人脸签到才有效果,其他可以忽略…
3.样式设置
4.其他设置
5.API文档
五、接口请求编写
1.后端接口请求编写
这是你的后端编写接口,请求人脸登录地址
参数说明:
2.运行流程图
添加人脸
登录验证
1.登录验证地址请求
请仔细阅读流程图
下面这个请求人脸登录地址,是通用的,你在后端你得放开这个接口,不管是登录状态还是为登录状态,得放行下面接口
最开始的时候,我们得先添加一张人脸才能验证人脸
@ApiOperation(value = "请求人脸登录地址")
@GetMapping("request/face/address/{userId}/{type}")
public R getFaceAddress(@PathVariable String userId,@PathVariable String type,@RequestParam(required = false) String custom) {
HttpClient client = HttpClients.createDefault();
HttpGet request = new HttpGet("http://localhost:8999/face-server/request/get/login/address?token="+token+"&userId="+userId+"&type="+type+"&custom="+custom);
try {
HttpResponse response = client.execute(request);
String responseBody = EntityUtils.toString(response.getEntity());
return R.ok().data("data",responseBody);
} catch (Exception e) {
e.printStackTrace();
return R.error();
}
}
返回示例
{
"msg": "成功",
"code": 200,
"data": "http://localhost:8999/face-server/face/login/D~XbYfwbEiVkAmw3NlOefhp4WuqgQS9bF!!ZKwMCowmrtA6HHkGIMHZyX9qoE8PsLmkOLUxsfdLzYJOMqzmQkQg==?custom=null"
}
- 前端拿到这个地址进行跳转开始认证
2.删除人脸
@ApiOperation(value = "根据用户唯一标识删除人脸")
@GetMapping("/delete/face/{userId}")
public R deleteFace(@PathVariable String userId) {
HttpClient client = HttpClients.createDefault();
HttpGet request = new HttpGet("http://localhost:8999/face-server/delete/face/"+token+"/"+userId);
try {
HttpResponse response = client.execute(request);
String responseBody = EntityUtils.toString(response.getEntity());
return R.ok();
} catch (Exception e) {
e.printStackTrace();
return R.error();
}
}
3.回调接口
@ApiOperation(value = "人脸的回调数据接口")
@PostMapping("request/face/loopback/address") // 配置中心配置的 如:http://localhost:8222/api/admin/request/face/loopback/address
public R loopbackAddress(@RequestBody String json) {
log.info("回调数据============{}",json);
userService.faceUser(json);
return R.ok();
}
4.前端验证调用流程
// 请求后端人脸登录地址
faceHandleLogin(){
user.requestFaceAddress('0','vef').then(res=>{
if (res.code === 20000){
let faceData = JSON.parse(res.data.data)
if (faceData && faceData.data){
// 拿到地址打开,开始验证
window.open(faceData.data,"_self")
}
}
})
},
// 解密方法
// data 返回的加密值
// currentKey 你当前的token,face-server的token
async decrypt(data, currentKey) {
try {
let result = decodeURIComponent(data);
result = result.replaceAll("!!", "/");
result = result.replaceAll("~", "+");
const rawData = atob(result); // Base64解码
const rawKey = new TextEncoder().encode(currentKey); // 密钥转换为Uint8Array
const iv = new Uint8Array(16); // 初始化向量(IV),对于AES-CBC模式,通常是16个零字节
const cryptoKey = await window.crypto.subtle.importKey(
"raw",
rawKey,
{ name: "AES-CBC", length: 256 },
false,
["decrypt"]
);
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: iv,
},
cryptoKey,
new Uint8Array(rawData.split('').map(char => char.charCodeAt(0))) // 将字符串转换为字节
);
return new TextDecoder().decode(decrypted);
} catch (e) {
console.error("解密失败:", e);
return null;
}
},
faceLogin(){
let userId = this.getQueryParamValue('t')
console.log("当前userId========",userId)
if (userId){
// 根据账号查询,返回账号密码,然后解密
// 然后调用原有登录方法,实现一个伪登录
// 大多数框架是password是加密的,得更换加密规则
user.requestFaceLogin({userId}).then(res=>{
if (res && res.code === 20000 && res.data){
this.decrypt(res.data.password,this.faceKey).then(resFace=>{
this.loginForm.username = res.data.username
this.loginForm.password = resFace
this.handleLogin()
})
}
})
}
},
// 拿到t的值,加密的值
// 这个方法主要是拿到当前浏览器的url后面那个拼接值
getQueryParamValue(key) {
const fullUrl = window.location.href;
let params = new URLSearchParams(window.location.hash.split('?')[1]);
if (!params.has(key)) {
const url = new URL(fullUrl);
params = new URLSearchParams(url.search);
if (!params.has(key) && url.hash.includes('?')) {
const hashQuery = url.hash.substring(url.hash.indexOf('?') + 1);
params = new URLSearchParams(hashQuery);
}
}
return params.has(key) ? params.get(key) : null;
},
// 你自己的登录方法
// 下面只是一个示例,具体替换为你自己的方法,
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
// debugger
this.loading = true
this.$store.dispatch('Login', this.loginForm).then(() => {
this.loading = false
this.$router.push('/dashboard')
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
}
5.后端加密工具类
可以把默认框架加密那套规则调整如下,用当前工具类加密
CryptoRequestUtil.encrypt(“你的密码”,“face-server 的token”)
加密完成后存入到数据
前端使用那个decrypt进行解密
public class CryptoRequestUtil {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
/**
* Encrypts the given data using AES/CBC/PKCS5Padding.
*
* @param data the data to encrypt
* @param key the encryption key
* @return the encrypted data encoded in Base64
* @throws Exception if an encryption error occurs
*/
public static String encrypt(String data, String key) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
IvParameterSpec iv = new IvParameterSpec(new byte[16]); // zero initialization vector for simplicity
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted).replace("/", "!!").replace("+", "~");
}
/**
* Decrypts the given Base64-encoded data using AES/CBC/PKCS5Padding.
*
* @param data the data to decrypt
* @param key the decryption key
* @return the decrypted string
* @throws Exception if a decryption error occurs
*/
public static String decrypt(String data, String key) throws Exception {
data = data.replace("!!", "/").replace("~", "+");
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
IvParameterSpec iv = new IvParameterSpec(new byte[16]); // zero initialization vector for simplicity
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
byte[] original = cipher.doFinal(Base64.getDecoder().decode(data));
return new String(original, StandardCharsets.UTF_8);
}
/**
* Decodes and decrypts URL-encoded and Base64-encoded data.
*
* @param data the data to decrypt
* @param key the decryption key
* @return the decrypted string or null if an error occurs
*/
public static String decryptFromUrl(String data, String key) {
try {
data = data.replace("%20", "+").replace("+", "~");
String decoded = URLDecoder.decode(data, StandardCharsets.UTF_8.name());
return decrypt(decoded, key);
} catch (Exception e) {
return null;
}
}
}
总结
Face-server是一款独立的人脸识别服务,通过API实现快速人脸登录,无需改动现有代码。它具备人脸验证、实时追踪用户人脸位置、检测人脸出现和消失,以及通过眨眼、摇头、张嘴等动作进行活体验证等功能,防止照片和视频攻击,保证登录安全。Face-server支持一键启动本地服务器,适用于Windows和Linux系统,安装简单快捷。其体积小巧但功能强大,资源占用少,适合各类项目应用。完全开源免费,提供灵活的后台配置,便于个性化设置人脸登录参数。Face-server通过提供全面而便捷的人脸识别服务,极大地简化了人脸登录的实现过程,提高了用户体验和系统安全性。
支持H5,手机端,兼容各种浏览器
报错解决
如果运行报错:
这是Java8 加密规则的一个缺陷,需要替换jdk里面的文件
找到jdk的位置
我的位置在这里,一般有jdk和jre文件
替换jdk下面相关文件
替换 local_policy.jar
替换 US_export_policy.jar
注意!!记得备份原有的,我是改了名 加了 ‘-a’
替换jre下面相关文件
jre跟jdk文件路径不同,
下面是我的Java jdk安装路径,默认选择你们的路径
jdk具体替换路径为:C:\Program Files\Java\jdk1.8.0_144\jre\lib\security
jre具体替换路径为:C:\Program Files\Java\jre1.8.0_144\lib\security
上面操作版本具体为 jdk1.8,版本之间可能存在微小差异,可能某些小伙伴路径并不是这样的,jdk下面只有一个文件夹,但是可以采用在当前jdk下面文件夹下面全局搜索, local_policy.jar,US_export_policy.jar 然后开始替换
文件下载
local_policy.jar,US_export_policy.jar
可以去oracel 官网下载
同时也可以去我的百度网盘下载