专家人脸登录开发完成

This commit is contained in:
袁帅
2022-09-07 16:20:59 +08:00
parent 6fbdeec3c0
commit 12b4460923
2 changed files with 179 additions and 119 deletions

View File

@ -55,7 +55,11 @@
// }); // });
function receiveMessageFromParent ( event ) { function receiveMessageFromParent ( event ) {
webcam.capture(); if(event.data == 'releaseCamera'){
location.reload();
}else if(event.data = 'capture'){
webcam.capture();
}
//$('#base64image').attr('src', 'data:image/jpg;base64,' + event.data.data); //$('#base64image').attr('src', 'data:image/jpg;base64,' + event.data.data);
}; };

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { Form, Button, Input, Row, Col, Modal, Spin, message } from 'antd'; import { Form, Button, Input, Row, Col, Modal, Spin, message, Tabs } from 'antd';
import { UserOutlined, LockOutlined, SafetyCertificateOutlined, VideoCameraOutlined } from '@ant-design/icons'; import { UserOutlined, LockOutlined, SafetyCertificateOutlined, VideoCameraOutlined } from '@ant-design/icons';
import './style.less'; import './style.less';
import { changePass, rgbToBase64 } from './service'; import { changePass, rgbToBase64 } from './service';
@ -23,15 +23,19 @@ export interface RgbParams {
const Index: React.FC<{}> = () => { const Index: React.FC<{}> = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [form2] = Form.useForm();
const [imgUrl, setImgUrl] = useState<any>(''); const [imgUrl, setImgUrl] = useState<any>('');
const [tmpToken, setTmpToken] = useState<any>(''); const [tmpToken, setTmpToken] = useState<any>('');
const remainingTime = 3 //刷新token的剩余时间单位小时 const remainingTime = 3 //刷新token的剩余时间单位小时
const [changeForm] = Form.useForm(); const [changeForm] = Form.useForm();
const [isModalVisible, setIsModalVisible] = useState<boolean>(false) const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
const [spinning, setSping] = useState<boolean>(false);//加载遮罩 const [spinning, setSping] = useState<boolean>(false);//加载遮罩
const [isFaceLogin, setIsFaceLogin] = useState<boolean>(false);
const video = useRef(); const video = useRef();
const whetherIE = useRef<boolean>(false); const whetherIE = useRef<boolean>(false);
const mediaStreamTrack = useRef<any>();
const { TabPane } = Tabs;
const [submitLoading, setSubmitLoading] = useState<boolean>(false);
const [faceLoginDisable, setFaceLoginDisable] = useState<boolean>(false);
const genRandomString = (len: number) => { const genRandomString = (len: number) => {
const text = 'abcdefghijklmnopqrstuvwxyz0123456789'; const text = 'abcdefghijklmnopqrstuvwxyz0123456789';
@ -84,8 +88,28 @@ const Index: React.FC<{}> = () => {
}); });
}; };
const onChange = (key: string) => {
if(key == '2'){
BrowserType();
InitMedia();
}else{
if(allowedToFaceLogin()){
if(whetherIE.current){
releaseCamera('faceLoginFrame');
}else{
mediaStreamTrack.current?.stop();
}
}
}
};
const releaseCamera = (id:string) => {
const childFrameObj = document.getElementById(id);
childFrameObj?.contentWindow?.postMessage('releaseCamera', '*');
}
const hanleFaceSubmit = async (multipartFiles: any, values: any) => { const hanleFaceSubmit = async (multipartFiles: any, values: any) => {
let userName = form.getFieldValue('userName'); let userName = form2.getFieldValue('userName');
if(whetherIE.current){ if(whetherIE.current){
if(!multipartFiles){ if(!multipartFiles){
const childFrameObj = document.getElementById('faceLoginFrame'); const childFrameObj = document.getElementById('faceLoginFrame');
@ -96,13 +120,17 @@ const Index: React.FC<{}> = () => {
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) { if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
refreshToken(res?.data) refreshToken(res?.data)
} else { } else {
releaseCamera('faceLoginFrame');
sessionStorage.setItem('Authorization', res?.data?.value); sessionStorage.setItem('Authorization', res?.data?.value);
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value); sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
sessionStorage.setItem('scope', res?.data?.scope); sessionStorage.setItem('scope', res?.data?.scope);
history.push('/redirect'); history.push('/redirect');
} }
} }
}); })
.finally(
() => {setSubmitLoading(false);}
);
} }
} }
else{ else{
@ -116,18 +144,23 @@ const Index: React.FC<{}> = () => {
hanleFaceSubmit(result, null); hanleFaceSubmit(result, null);
}) })
}else{ }else{
setSubmitLoading(true);
await ZjfakeFaceLogin({ userName, multipartFiles }).then((res) => { await ZjfakeFaceLogin({ userName, multipartFiles }).then((res) => {
if (res?.success) { if (res?.success) {
if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) { if (moment(res?.data?.expiration).diff(moment(), 'hours') < remainingTime) {
refreshToken(res?.data) refreshToken(res?.data)
} else { } else {
mediaStreamTrack.current?.stop();
sessionStorage.setItem('Authorization', res?.data?.value); sessionStorage.setItem('Authorization', res?.data?.value);
sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value); sessionStorage.setItem('refreshToken', res?.data?.refreshToken.value);
sessionStorage.setItem('scope', res?.data?.scope); sessionStorage.setItem('scope', res?.data?.scope);
history.push('/redirect'); history.push('/redirect');
} }
} }
}); })
.finally(
() => {setSubmitLoading(false);}
);
} }
} }
} }
@ -158,19 +191,6 @@ const Index: React.FC<{}> = () => {
}) })
} }
} }
//登录模式改变事件
const LoginModeChangeEvent = (mode: any) => {
switch(mode){
case 1:
setIsFaceLogin(true);
InitMedia();
break;
case 2:
setIsFaceLogin(false);
break;
}
}
//浏览器类型 //浏览器类型
const BrowserType = () =>{ const BrowserType = () =>{
//取得浏览器的userAgent字符串 //取得浏览器的userAgent字符串
@ -210,7 +230,6 @@ const Index: React.FC<{}> = () => {
} }
//初始化video //初始化video
const InitMedia = () => { const InitMedia = () => {
BrowserType();
if(!whetherIE.current){ if(!whetherIE.current){
InitUserMedia({video : {width: 480, height: 320}}, success, error); InitUserMedia({video : {width: 480, height: 320}}, success, error);
} }
@ -233,13 +252,19 @@ const Index: React.FC<{}> = () => {
} }
//调用媒体设备成功回调方法 //调用媒体设备成功回调方法
const success = (stream: any) => { const success = (stream: any) => {
//兼容webkit核心浏览器 var result = stream.getVideoTracks().some(function(track:any) {
const CompatibleURL = window.URL || window.webkitURL; return track.enabled && track.readyState === 'live';
//将视频流设置为video元素的源 });
console.log(stream); if (result) {
//video.src = CompatibleURL.createObjectURL(stream); //兼容webkit核心浏览器
video.current.srcObject = stream; const CompatibleURL = window.URL || window.webkitURL;
video.current.play(); //将视频流设置为video元素的源
console.log(stream);
//video.src = CompatibleURL.createObjectURL(stream);
video.current.srcObject = stream;
mediaStreamTrack.current = stream.getTracks()[0];
video.current.play();
}
} }
//调用媒体设备失败回调方法 //调用媒体设备失败回调方法
const error = (error:any) => { const error = (error:any) => {
@ -262,16 +287,46 @@ const Index: React.FC<{}> = () => {
//RgbToBase64 //RgbToBase64
const RgbToBase64 = async (image:any) =>{ const RgbToBase64 = async (image:any) =>{
setSubmitLoading(true);
await rgbToBase64({image}).then(res => { await rgbToBase64({image}).then(res => {
const _blob = base64ToBlob( 'data:image/jpg;base64,' + res.data); const _blob = base64ToBlob( 'data:image/jpg;base64,' + res.data);
hanleFaceSubmit(_blob, null); hanleFaceSubmit(_blob, null);
}).catch(e=>{
setSubmitLoading(false);
}); });
} }
//是https或者是本地
const httpsOrLocal = () => {
let protocol = document.location.protocol;
if(protocol == 'https'){
return true;
}else{
let host = window.location.hostname;
if(host == '127.0.0.1' || host == 'localhost'){
return true;
}
}
return false;
}
//是否允许人脸登录
const allowedToFaceLogin = () => {
let browseType = BrowserType()
if((browseType == 11 || browseType == -1) && httpsOrLocal()){
return true;
}
return false;
}
useEffect(() => { useEffect(() => {
cookie.remove('mall3_token'); cookie.remove('mall3_token');
sessionStorage.clear(); sessionStorage.clear();
changeCaptcha(); changeCaptcha();
if(!allowedToFaceLogin()){
setFaceLoginDisable(true);
}
}, []); }, []);
return ( return (
@ -284,109 +339,110 @@ const Index: React.FC<{}> = () => {
</div> </div>
<div className="main"> <div className="main">
<div className="text"> <div className="text">
<h3> </h3> <Tabs defaultActiveKey="1" onChange={onChange} size = {'large'}>
{!isFaceLogin ? ( <TabPane tab="账号密码登录" key="1">
<Form <Form
name="basic" name="basic"
className="form-box" className="form-box"
initialValues={{ remember: true }} initialValues={{ remember: true }}
form={form} form={form}
onFinish={handleSubmit} onFinish={handleSubmit}
// onFinishFailed={onFinishFailed} // onFinishFailed={onFinishFailed}
> >
<Form.Item
label=""
name="userName"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input
prefix={
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入用户名"
/>
</Form.Item>
<Form.Item
label=""
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password
prefix={
<LockOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入密码"
addonAfter={<VideoCameraOutlined onClick={() => LoginModeChangeEvent(1)}/>}
/>
</Form.Item>
<Row>
<Col span={14}>
<Form.Item <Form.Item
label="" label=""
name="captcha" name="userName"
rules={[{ required: true, message: '请输入验证码!' }]} rules={[{ required: true, message: '请输入用户名!' }]}
> >
<Input <Input
prefix={ prefix={
<SafetyCertificateOutlined <UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
style={{ fontSize: '18px' }}
className="site-form-item-icon"
/>
} }
placeholder="请输入验证码" placeholder="请输入用户名"
/>
</Form.Item>
<Form.Item
label=""
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password
prefix={
<LockOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入密码"
/> />
</Form.Item> </Form.Item>
</Col>
<Col span={10}>
<img className="verification" onClick={() => changeCaptcha()} src={imgUrl} />
</Col>
</Row>
{/* <Form.Item className="remember" name="remember" valuePropName="checked"> <Row>
<Checkbox>记住密码</Checkbox> <Col span={14}>
</Form.Item> */} <Form.Item
<Form.Item> label=""
<Button type="primary" className="w100" htmlType="submit"> name="captcha"
rules={[{ required: true, message: '请输入验证码!' }]}
</Button> >
</Form.Item> <Input
</Form>):( prefix={
<Form <SafetyCertificateOutlined
name="basic" style={{ fontSize: '18px' }}
className="form-box" className="site-form-item-icon"
initialValues={{ remember: true }} />
form={form} }
onFinish={hanleFaceSubmit.bind(this, null)} placeholder="请输入验证码"
// onFinishFailed={onFinishFailed} />
> </Form.Item>
<Form.Item </Col>
label="" <Col span={10}>
name="userName" <img className="verification" onClick={() => changeCaptcha()} src={imgUrl} />
rules={[{ required: true, message: '请输入用户名!' }]} </Col>
> </Row>
<Input
prefix={ {/* <Form.Item className="remember" name="remember" valuePropName="checked">
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" /> <Checkbox>记住密码</Checkbox>
} </Form.Item> */}
placeholder="请输入用户名" <Form.Item>
addonAfter = {<LockOutlined onClick={() => LoginModeChangeEvent(2)}/>} <Button type="primary" className="w100" htmlType="submit">
/>
</Form.Item> </Button>
{/* 加载摄像头 */} </Form.Item>
<Form.Item> </Form>
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>):(<FrameFaceLogin faceCompareEvent = {RgbToBase64}/>)} </TabPane>
</Form.Item> <TabPane tab="人脸识别登录" key="2" disabled = {faceLoginDisable}>
<Form.Item> <Form
{/* onClick={() => {hanleFaceSubmit(null, null);}} */} name="basic2"
<Button type="primary" className="w100" htmlType="submit"> className="form-box"
initialValues={{ remember: true }}
</Button> form={form2}
</Form.Item> onFinish={hanleFaceSubmit.bind(this, null)}
</Form>)} // onFinishFailed={onFinishFailed}
>
<Form.Item
label=""
name="userName"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input
prefix={
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入用户名"
/>
</Form.Item>
{/* 加载摄像头 */}
<Form.Item>
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>):(<FrameFaceLogin faceCompareEvent = {RgbToBase64}/>)}
</Form.Item>
<Form.Item>
{/* onClick={() => {hanleFaceSubmit(null, null);}} */}
<Button type="primary" className="w100" loading = {submitLoading} htmlType="submit">
</Button>
</Form.Item>
</Form>
</TabPane>
</Tabs>
</div> </div>
</div> </div>
{/* <div className="footer">版权所有:中国联合网络通信有限公司</div> */}
<Modal <Modal
title="修改密码" title="修改密码"
visible={isModalVisible} visible={isModalVisible}