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