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
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()
|