You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
14 KiB

import base64
import io
import requests
import cv2
import hashlib
import numpy as np
from PIL import Image
from conf import setting
from fastapi import APIRouter, Depends, BackgroundTasks, Request
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from arcsoft.arcface import FaceRecognitionEngine
from arcsoft.exception import FaceNotFoundException, FaceMoreThanOneException, ArcSoftCallException, NonLivingException, \
UserNotFoundException
from endpoints.web.RTLS import getOnce
from helper import respond_to, login_required
from helper.log import record_log
from helper.tool import play_sound
from helper.utils import timezone_now, encrypt_md5
from models import User, Log, PlatformSecurity
from endpoints.secure import LoginSession
from helper.websocket_manage import manager
router = APIRouter(prefix='/sessions')
class SignInModel(BaseModel):
username: str
password: str
class FaceModel(BaseModel):
raw: str # base64的人脸图片
class FaceRebindModel(BaseModel):
source_id: str
target_id: str
class SignOutModel(BaseModel):
user_id: str
#度目添加人脸
def face_data_to_client(ip, frame, user_id, user_name, pwd="123456"):
"""
把人脸数据发送到终端
:param url: 请求url
:param frame: 人脸
:param user_id: 用户id
:param user_name: 用户名称
:param pwd: 终端密码
:return:
"""
req_url = "http://{}:8080/userManage/addUser".format(ip)
img_str = change_type(frame)
headers = {
'Connection': 'close'
}
data = {
"pass": hashlib.md5(pwd.encode()).hexdigest(),
"user_id": user_id.replace('-', ''),
"image_content": img_str,
"image_type": "image",
"user_info": {
"name": user_name,
"user_type": 1,
"phone_number": ""
},
"action_type": "APPEND",
"quality_control": "LOW",
}
try:
r = requests.post(req_url, json=data, headers=headers, timeout=1)
data = r.json()
if data['code'] >= 0:
print(data)
return 1
else:
print(data)
return 0
except Exception as e:
print(e)
return 0
# ndarray 与 base64
def change_type(self, frame):
# frame = cv2.resize(frame,(960,960))
retval, img_buffer = cv2.imencode('.jpg', frame)
img_str = base64.b64encode(img_buffer)
return str(img_str, encoding='utf-8')
@router.post('', summary='账号密码登录')
async def create(model: SignInModel):
# 审核人:林长青 2023-05-30
user = await User.get_or_none(username=model.username.strip())
if user is None:
return respond_to(code=404, desc='账号尚未注册')
if user.locked:
return respond_to(code=423, desc='账号已被锁定')
source = await PlatformSecurity.all().first()
if 0 < source.login_frozen_count <= user.login_frozen_count:
return respond_to(code=423, desc='账号已被冻结')
if not encrypt_md5(model.password) == user.password_digest:
if source.login_frozen_count > 0:
user.login_frozen_count = user.login_frozen_count + 1
user.last_attempt_at = timezone_now()
await user.save(update_fields=['login_frozen_count', 'last_attempt_at'])
return respond_to(code=403,
desc=f'密码错误!{source.login_frozen_count - user.login_frozen_count + 1}次后将被系统冻结。')
return respond_to(code=403, desc='账号与密码不匹配')
record = {"user_id": user.id, "users": user.username, "kind": "用户", "comment": f"用户{user.username},登录成功"}
await record_log(**record)
user.login_frozen_count = 0
user.last_attempt_at = None
user.last_login_at = timezone_now()
await user.save(update_fields=['login_frozen_count', 'last_attempt_at', 'last_login_at'])
# 广播登录结果
LoginSession.token = user.id
await manager.broadcast_json("login", data=jsonable_encoder({"user": await user.profile, "msg": f"[{user.username}]登录成功"}))
return respond_to(data=await user.profile)
@router.post('/face', summary='人脸识别登录')
async def create(model: FaceModel):
# 审核人:林长青 2023-05-30
bin = base64.b64decode(model.raw)
image = Image.open(io.BytesIO(bin))
buffer = np.array(image)
users = await User.filter(face__isnull=False).values_list('id', 'face')
with FaceRecognitionEngine() as engine:
try:
user_id = engine.login(buffer, users)
except UserNotFoundException:
return respond_to(code=400, desc='人脸信息尚未绑定')
except ArcSoftCallException:
return respond_to(code=400, desc='人脸底层接口无法调用')
except FaceNotFoundException:
return respond_to(code=400, desc='未检测到人脸信息')
except FaceMoreThanOneException:
return respond_to(code=400, desc='检测到多张人脸')
except NonLivingException:
return respond_to(code=400, desc='检测到非活体')
user = await User.get_or_none(id=user_id)
if user.locked:
return respond_to(code=423, desc='账号已被锁定')
record = {"user_id": user.id, "users": user.username, "kind": "用户", "comment": f"用户{user.username},登录成功"}
await record_log(**record)
user.login_frozen_count = 0
user.last_attempt_at = None
user.last_login_at = timezone_now()
await user.save(update_fields=['login_frozen_count', 'last_attempt_at', 'last_login_at'])
# 广播登录结果
LoginSession.token = user.id
await manager.broadcast_json("login", data=jsonable_encoder({"user": await user.profile, "msg": f"[{user.username}]人脸登录成功"}))
return respond_to(data=await user.profile)
@router.put('/face/{target_user_id}', summary='人脸信息绑定', dependencies=[Depends(login_required)])
async def update(request: Request, model: FaceModel, target_user_id: str, tasks: BackgroundTasks):
# 审核人:林长青 2023-05-30
bin = base64.b64decode(model.raw)
image = Image.open(io.BytesIO(bin))
buffer = np.array(image)
users = await User.filter(face__isnull=False).values_list('id', 'face')
with FaceRecognitionEngine() as engine:
try:
user_id = engine.login(buffer, users)
if str(user_id) != target_user_id:
return respond_to(code=409, desc='当前人脸已与其他账号绑定, 是否确认更换?', data={'source_id': user_id})
user = await User.get(id=target_user_id)
user.face = engine.feature(buffer)
await user.save(update_fields=['face'])
try:
for i in setting.DUMU_LIST:
face_data_to_client(ip=i, frame=buffer,user_id=user.id, pwd='123456',user_name=user.username)
except Exception as e:
print(e)
tasks.add_task(Log.write, '用户',
{'user_id': request.state.current_user.id, 'comment': f'{user.nickname}重新绑定人脸信息'})
record = {"user_id": user.id, "users": user.username, "kind": "用户",
"comment": f"用户{user.username},绑定人脸信息"}
await record_log(**record)
return respond_to()
except UserNotFoundException:
user = await User.get(id=target_user_id)
user.face = engine.feature(buffer)
await user.save(update_fields=['face'])
tasks.add_task(Log.write, '用户',
{'user_id': request.state.current_user.id, 'comment': f'{user.nickname}绑定人脸信息'})
record = {"user_id": user.id, "users": user.username, "kind": "用户",
"comment": f"用户{user.username},绑定人脸信息"}
await record_log(**record)
return respond_to()
except ArcSoftCallException:
return respond_to(code=400, desc='接口调用失败')
except FaceNotFoundException:
return respond_to(code=400, desc='未检测到人脸信息')
except FaceMoreThanOneException:
return respond_to(code=400, desc='检测到多张人脸')
except NonLivingException:
return respond_to(code=400, desc='检查到非活体')
@router.patch('/face', summary='人脸信息更换绑定', dependencies=[Depends(login_required)])
async def update(request: Request, model: FaceRebindModel, tasks: BackgroundTasks):
# 审核人:林长青 2023-05-30
source_user = await User.get(id=model.source_id)
target_user = await User.get(id=model.target_id)
target_user.face = source_user.face
source_user.face = None
await target_user.save(update_fields=['face'])
await source_user.save(update_fields=['face'])
tasks.add_task(Log.write, '用户',
{'user_id': request.state.current_user.id, 'comment': f'{target_user.nickname}更换人脸信息'})
return respond_to()
@router.post('/logout', summary='登出')
async def create(model: SignOutModel):
user_id = model.user_id
# 用户登出
user_obj = await User.get_or_none(id=user_id)
if not user_obj:
return respond_to(code=404, desc='未查询到用户信息')
LoginSession.user_id = ""
await manager.broadcast_json("logout", data={"user_id": str(user_id), "msg": f"[{user_obj.username}]登出成功"})
return respond_to(desc="登出完成")
@router.post('/login_key', summary='账号标识登录')
async def loginKey():
return
ridt_ida = await getOnce()
user = await User.get_or_none(login_key=ridt_ida)
if user is None:
return respond_to(code=404, desc='账号尚未注册')
if user.locked:
return respond_to(code=423, desc='账号已被锁定')
source = await PlatformSecurity.all().first()
if 0 < source.login_frozen_count <= user.login_frozen_count:
return respond_to(code=423, desc='账号已被冻结')
record = {"user_id": user.id, "users": user.username, "kind": "用户", "comment": f"用户{user.username},登录成功"}
await record_log(**record)
user.login_frozen_count = 0
user.last_attempt_at = None
user.last_login_at = timezone_now()
await user.save(update_fields=['login_frozen_count', 'last_attempt_at', 'last_login_at'])
# 广播登录结果
LoginSession.token = user.id
await manager.broadcast_json("login", data=jsonable_encoder({"user": await user.profile, "msg": f"[{user.username}]登录成功"}))
play_sound("登陆成功.wav")
return respond_to(data=await user.profile)
class CardModel(BaseModel):
raw: str
@router.post('/card_login', summary='卡片登录')
async def create(model: CardModel):
user = await User.get_or_none(raw=model.raw)
if not user:
return respond_to(code=400, desc='卡片信息尚未绑定')
if user.locked:
return respond_to(code=423, desc='账号已被锁定')
record = {"user_id": user.id, "users": user.username, "kind": "用户",
"comment": "登录客户端:RMS系统,登录方式:卡片"}
await record_log(**record)
user.login_frozen_count = 0
user.last_attempt_at = None
user.last_login_at = timezone_now()
await user.save(update_fields=['login_frozen_count', 'last_attempt_at', 'last_login_at'])
return respond_to(data=await user.profile)
class BindCardModel(BaseModel):
target_user_id:str
raw: str
@router.post('/card_bind', summary='卡片信息绑定', dependencies=[Depends(login_required)])
async def update(request: Request, model: BindCardModel):
user = await User.get_or_none(raw=model.raw)
if not user:
user = await User.get(id=model.target_user_id)
user.raw = model.raw
await user.save(update_fields=['raw'])
# tasks.add_task(Log.write, '用户',
# {'user_id': request.state.current_user.id, 'comment': f'{user.username}绑定卡片信息'})
# record = {"user_id": user.id, "users": user.username, "kind": "用户",
# "comment": f"{user.username}绑定卡片信息"}
# await record_log(**record)
return respond_to()
else:
if user.id != model.target_user_id:
return respond_to(code=409, desc='当前卡片已与其他账号绑定, 是否确认更换?', data={'source_id': user.id,'source_name':user.name})
else:
user = await User.get(id=model.target_user_id)
user.raw = model.raw
await user.save(update_fields=['login_key'])
# tasks.add_task(Log.write, '用户',
# {'user_id': request.state.current_user.id, 'comment': f'{user.username}重新绑定卡片信息'})
record = {"user_id": user.id, "users": user.username, "kind": "用户",
"comment": f"{user.username}重新绑定卡片信息"}
await record_log(**record)
return respond_to()
class CardRebindModel(BaseModel):
source_id: str
target_id: str
@router.post('/card_change', summary='卡片信息更换绑定', dependencies=[Depends(login_required)])
async def update(request: Request, model: CardRebindModel):
source_user = await User.get(id=model.source_id)
target_user = await User.get(id=model.target_id)
target_user.raw = source_user.raw
source_user.raw = None
await source_user.save(update_fields=['raw'])
await target_user.save(update_fields=['raw'])
# tasks.add_task(Log.write, '用户',
# {'user_id': request.state.current_user.id, 'comment': f'{target_user.username}更换卡片信息'})
# record = {"user_id": request.state.current_user.id, "users": request.state.current_user.username, "kind": "用户",
# "comment": f"{request.state.current_user.username}更换卡片信息"}
# await record_log(**record)
return respond_to()