如何实现刷脸登录

如何实现刷脸登录

本文主要采用百度AI平台的人脸识别技术实现,原理比较简单,注册面部到人脸库,之后拍照获取照片,在人脸库中查找相似的图片,如果相似度超过设定的阈值,则认为存在这个用户,这里主要介绍下如何获取access_token,并建立自己的人脸库。并且对自己的人脸库进行管理以及登录功能。

一、首先注册百度云账号
在这里插入图片描述

二、注册完之后登录找到 “>” ->人工智能->人脸识别
在这里插入图片描述
在这里插入图片描述
三、我们来创建自己的第一个人脸库应用,点击上图的创建应用
在这里插入图片描述
填写上基本信息,人脸识别默认会全选,创建完成之后,点击查看应用详情
在这里插入图片描述
需要注意的一点:AppID,API Key,Secret Key是我们需要用到的几个。可以先复制出来

三、练习
在实现刷脸登录时,首先我们来练习如何管理刚刚创建的人脸库

// An highlighted block
< dependency>
 <groupId>com. baidu. aip</ groupId>
<artifactId>java-sdk</ artifactId>
<version>4.8. 0</ version>
</ dependency>

1、人脸注册

首先在Test里面创建一个类FaceTest
在这里插入图片描述
以上红框的地方就是之前自己创建人脸库的时候,事先让大家把AppID,API Key,Secret Key复制出来的数据,完成上面的代码后可以在自己的人脸库查看到自己上传上去的图片:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
2、人脸检测
我们在登录的时候,首先要判断图片是否具有面部信息
在这里插入图片描述
完成上述代码后运行测试,查看控制台如下则成功:
在这里插入图片描述
如果图片中存在人脸则出现以下输出:
在这里插入图片描述
3、人脸搜索
根据用户上传的图片和指定人脸库中的所有图片进行比较,获取相似度最高的一个或某几个进行评分,也就是一开始所说的阈值,如果阈值达到了我们说设置的则成功,代码如下:
在这里插入图片描述
完成以上代码运行,会返回数据:
在这里插入图片描述
一般我们设置的阈值大于80分才认为是同一个人,很显然上面的评分不符合我们的要求,则过滤掉

4、人脸更新
在我们使用软件的过程中,我们的面部可能会有所变化,为了防止不准确,我们会更新人脸库的照片,( 注册和更新的代码基本一样 注册时是addUser 更新时是updateUser)
在这里插入图片描述
完成以上代码运行即可更新完成

三、刷脸登录
我们在进行刷脸登录的时候,首先会创建一个二维码,使用手机扫描二维码进行人脸赵信,(二维码的内容可以放前端调用摄像头的地址,这样扫码之后就会打开手机摄像头),以下是刷脸登录的流程图:
在这里插入图片描述
在此之前先熟悉一下二维码的生成:
加入依赖:

// An highlighted block
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.4.0</version>
</dependency>

在这里插入图片描述
在这里插入图片描述
完成上述代码即可

接下来就是刷脸登录的核心代码:
在进行人脸登录的时候首先将一张图片上传到百度云,在进行人脸上传的时候我们可以用户id作为百度云照片的id,因为我们在搜索成功之后,会返回此id,这样可以根据id获取用户的信息登录

// An highlighted block

   @RequestMapping(value = "/user/upload/{id}",method = RequestMethod.POST)
   public Result upload(@PathVariable String id,@RequestParam(name = "file") MultipartFile file)throws IOException {
       //调用service保存图片,同时获取图片访问地址
        String imgUrl = userService.uploadImage(id,file);
        //返回数据
        return new Result(ResultCode.SUCCESS,imgUrl);
   }
}
// An highlighted block
//用户头像上传
//注册到百度云人脸库
//调用到百度云接口,判断是否已注册
@Override
public String uploadImage(String id, MultipartFile file)throws IOException {
    //根据id查询用户
     User user = userDao.findById(id).get();
   // 使用DataURL存储图片,对图片进行base64编码
    String encode = "data:image/png;base64," + Base64.encode(file.getBytes());
    //将图片上传到七牛云存储
   // String encode = new QiNiuUploadUtil().upload(user.getId(), file.getBytes());
    //更新用户头像返回路径
    user.setStaffPhoto(encode);
    String base64 = Base64.encode(file.getBytes());
    //判断是否已注册
    Boolean b = baiDuYunUtil.faceExiet(id);
     if (b){
         baiDuYunUtil.faceUpdate(id,base64);
     }
    baiDuYunUtil.faceRegister(id,base64);
    userDao.save(user);
    return encode;
}

QRCodeUtil 【二维码工具类】

// An highlighted block
public class QRCodeUtil {
    //生成base64二维码
    public String createQRcode(String content)throws IOException{
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try{
           //生成二维码
            QRCodeWriter qrCodeUtil = new QRCodeWriter();
            //基本配置
            //二维码信息
            //图片类型
            //宽度
            //长度
            BitMatrix bitMatrix = qrCodeUtil.encode(content, BarcodeFormat.QR_CODE,200,200);
            //创建ByteArrayOutputStream
            //将二维码数据以byte数组保存到ByteArrayOutputStream
            BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
            ImageIO.write(image,"png",os);
           return new String("data:image/png;base64," + Base64.encode(os.toByteArray()));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            os.close();
        }
        return null;
    }
}

// An highlighted block
public class QRCode implements Serializable {
    public static final String serialVersionUID = "43753879088123002L";
    //随机生成码
    private String  code;
    //base64二维码文件
    private String file;
}

// An highlighted block
public class FacLoginResult implements Serializable {
    //二维码使用状态:-1:未使用,0:登录失败,1:登陆成功
    private String state;
    //登录信息
    private String  token ;
    //用户id
    private int userId;

    public FacLoginResult(String state,String  token ,int userId){
        this.state = state;
        this.token = token;
        this.userId = userId;
    }
    public FacLoginResult(String state){
        this.state = state;
    }
}

BaiDuYunUtil 【百度云工具类】

// An highlighted block
public class BaiDuYunUtil {
    @Value("${ai.appId}")
    private String APP_ID;
    @Value("${ai.API_KEY}")
    private String API_KEY;
    @Value("${ai.secretKey}")
    private String secretKey;
    @Value("${ai.imageType}")
    private String IMAGE_TYPE;
    @Value("${ai.groundId}")
    private String GROUND_ID;

    private static AipFace aipFace;

    private  HashMap<String, String> map = new HashMap<>();
    public BaiDuYunUtil(){
        map.put("quality_control", "NORMAL");//图片质量:NONE,LOW,NORMAL,HIGH
        map.put("liveness_control", "LOW");//活体检测
   }
   @PostConstruct
    public void init(){
       //创建java代码和百度云交互的client对象
       aipFace = new AipFace(APP_ID, API_KEY, secretKey);
   }
   //人脸注册
    //String.valueOf(userId)  因为数据库的id是int类型  建议使用String
    public Boolean faceRegister(int userId, String image){
        JSONObject jsonObject = aipFace.addUser(image, IMAGE_TYPE, GROUND_ID, String.valueOf(userId), map);
        Integer integer = jsonObject.getInt("error_code");
        return integer == 0 ? true : false;
    }
    //人脸检测
    /**
     * 人脸检测:判断上传图片中是否具有面部头像
     */
    public Boolean faceCheck(String image) throws JSONException {
        JSONObject res = aipFace.detect(image, IMAGE_TYPE, map);
        if (res.has("error_code") && res.getInt("error_code") == 0) {
            JSONObject resultObject = res.getJSONObject("result");
            Integer faceNum = resultObject.getInt("face_num");
            return faceNum == 1?true:false;
        }else{
            return false;
        }
    }

    /**
     *  人脸更新 :更新人脸库中的用户照片
     */
    public Boolean faceUpdate(int userId, String image) throws JSONException {
        // 人脸更新
        JSONObject res = aipFace.updateUser(image, IMAGE_TYPE, GROUND_ID, String.valueOf(userId), map);
        Integer errorCode = res.getInt("error_code");
        return errorCode == 0 ? true : false;
    }
    //判断用户是否注册百度云
    public boolean faceExiet(int userId){
        JSONObject user = aipFace.getUser(String.valueOf(userId), GROUND_ID, null);
        Integer integer = user.getInt("error_code");
        return integer == 0 ? true:false;
    }
    //人脸查找:评分大于80,则同意
    public int faceSearch(String image){
        JSONObject jsonObject = aipFace.search(image,IMAGE_TYPE,"ihrm", map);
        if (jsonObject.has("error_code") && jsonObject.getInt("error_code") == 0){
            JSONObject result = jsonObject.getJSONObject("result");
            JSONArray jsonArray = result.getJSONArray("user_list");
            if (jsonArray.length() > 0){
                JSONObject user = jsonArray.getJSONObject(0);
                double score = user.getDouble("score");
                if (score > 80 ){
                    return user.getInt("user_id");
                }
            }
        }
        return 0;
    }
}

Conroller【控制层】

// An highlighted block
@RestController
@RequestMapping("/sys/faceLogin")
@Api(tags = "用户刷脸登录")
public class FaceLoginController {

    @Autowired
    private FaceLoginService faceLoginService;
    @Autowired
    private BaiDuYunUtil baiDuYunUtil;

    /**
     * 获取刷脸登录二维码
     */
    @GetMapping(value = "/qrcode")
    @ApiOperation(value = "获取二维码")
    public DataResult qrcode() throws Exception {
        QRCode qrCode = faceLoginService.getQRCode();
        return DataResult.getResult(BaseResponseCode.SUCCESS,qrCode);
    }
    /**
     * 检查二维码:登录页面轮询调用此方法,根据唯一标识code判断用户登录情况
     */
    @GetMapping(value = "/qrcode/{code}")
    @ApiOperation(value = "检查二维码")
    public DataResult qrcodeCeck(@PathVariable(name = "code") String code) throws Exception {
        FacLoginResult checkQRCode = faceLoginService.checkQRCode(code);
        return new DataResult(BaseResponseCode.SUCCESS , checkQRCode);
    }
    /**
     * 人脸登录:根据落地页随机拍摄的面部头像进行登录
     *          根据拍摄的图片调用百度云AI进行检索查找
     */
    @PostMapping(value = "/{code}")
    @ApiOperation(value = "人脸登录")
    public DataResult loginByFace(@PathVariable(name = "code") String code, @RequestParam(name = "file") MultipartFile attachment) throws Exception {
        String userId = faceLoginService.loginByFace(code, attachment);
        if (userId != null){
            return new DataResult(BaseResponseCode.SUCCESS);
        }else {
            return new DataResult(BaseResponseCode.FAIL);
        }
    }
    /**
     * 图像检测,判断图片中是否存在面部头像
     */
    @RequestMapping(value = "/checkFace", method = RequestMethod.POST)
    @ApiOperation(value = "图像检测")
    public DataResult checkFace(@RequestParam(name = "file") MultipartFile attachment) throws Exception {
        String image = Base64Util.encode(attachment.getBytes());
        Boolean isExist = baiDuYunUtil.faceCheck(image);
        if (isExist){
            return new DataResult(BaseResponseCode.SUCCESS);
        }else{
            return new DataResult(BaseResponseCode.FAIL);
        }
    }
}
FaceLoginService 【业务层】
public interface FaceLoginService {
    //创建二维码
    public QRCode getQRCode() throws Exception;

    //根据唯一标识,查询用户是否登录成功
    public FacLoginResult checkQRCode(String code);

    //扫描二维码之后,使用拍摄照片进行登录
    public String loginByFace(String code, MultipartFile attachment) throws Exception;
}

FaceLoginServiceImpl 【业务实现层】

// An highlighted block
@Service
public class FaceLoginServiceImpl implements FaceLoginService {
    @Value("${qr.url}")
    private String url;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private QRCodeUtil qrCodeUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private BaiDuYunUtil baiDuYunUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private SysPermissionService sysPermissionService;

    //创建二维码
    public QRCode getQRCode() throws Exception {
        //创建二维码唯一标识
        String code = idWorker.nextId()+"";
        //二维码内容
        String content = url + "?code=" + code;
        System.out.println(content);
        String file = qrCodeUtil.createQRcode(content);
        System.out.println(file);
        //将二维码存入redis
        FacLoginResult result = new FacLoginResult("-1");
        redisUtil.set(getCacheKey(code),result,10,TimeUnit.MINUTES);
        return new QRCode(code , file);
    }

    //根据唯一标识,查询用户是否登录成功
    public FacLoginResult checkQRCode(String code) {
        String key = getCacheKey(code);
        FacLoginResult faceLoginResult = (FacLoginResult) redisUtil.get(key);
        return faceLoginResult;
    }

    //扫描二维码之后,使用拍摄照片进行登录
    public String loginByFace(String code, MultipartFile attachment) throws Exception {
        //1.调用百度云AI查询当前的用户
        int userId = baiDuYunUtil.faceSearch(Base64Util.encode(attachment.getBytes()));
        //2.自动登录
        FacLoginResult result = new FacLoginResult("0");
          if (userId != 0){
            User user = userMapper.findById(userId);
            if (user != null){
               String token = JwtUtil.sign(user.getName(),user.getPassword(),userId);
                //将token存入redis缓存,并设置过期时间
                redisUtil.set(Constant.PREFIX_USER_TOKEN + user.getName(),token,Constant.TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
                //根据id获取权限集合
//                List<String> PermissionsList = userMapper.getUserPermissionsList(user.getId());
                Set<String> PermissionsList = sysPermissionService.getPermissionsByUserId(userId);
                redisUtil.set(Constant.JWT_PERMISSIONS_KEY +user.getName(),PermissionsList,Constant.TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
                //根据id获取角色集合
                List<String> RolesList = userMapper.getUserRolesList(user.getId());
                //将RolesList中的权限数据放入redis,并设置权限过期时间
                redisUtil.set(Constant.JWT_ROLES_KEY +user.getName(),RolesList,Constant.TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
                AsyncManager.me().execute(AsyncFactory.insertLog(user.getName(),Constant.LOGIN_SUCCESS,"登录成功"));
                result = new FacLoginResult("1" , token , userId);
            }else {
                throw new BusinessException(4045,"用户未注册");
            }
          }
        //3.修改二维码的状态
        redisUtil.set(getCacheKey(code),result , 10 , TimeUnit.MINUTES);
        return  String.valueOf(userId);
    }

    //构造缓存key
    private String getCacheKey(String code) {
        return "qrcode_" + code;
    }
}

完成以上代码之后我们来进行测试,由于前端没有进行调用摄像头,我们可以上传一张图片进行测试,首先打开postman,由于我的项目整合了swagger,所以我直接在swagger进行测试

1、先获取二维码的code
在这里插入图片描述
1、将获取的code,填入之后进行登录
在这里插入图片描述
返回操作成功,也生成了token,由此刷脸登录成功!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值