更新数据库加密相关操作

This commit is contained in:
2025-01-15 13:16:48 +08:00
parent 81069274be
commit 262ecc4f5e
12 changed files with 383 additions and 90 deletions

View File

@@ -9,8 +9,15 @@ use common\core\BaseAdminController;
use common\enums\UserRoleEnum;
use common\helpers\ArrayHelper;
use common\models\oldDb\AdminAccessToken;
use common\models\oldDb\DoctorInfo;
use common\models\oldDb\DoctorPatient;
use common\models\oldDb\LeadInfo;
use common\models\oldDb\Role;
use common\models\oldDb\ServInfo;
use common\models\oldDb\Store;
use common\models\oldDb\User;
use common\models\oldDb\UserPatient;
use common\modelsgii\oldDb\PharmacistInfo;
use common\services\SmsService;
use Yii;
use yii\base\Exception;
@@ -20,10 +27,100 @@ class LoginController extends BaseAdminController
public $modelClass = Admin::class;
public $enableCsrfValidation = false;
public $defaultAction = 'register';
public $optional = ['register', 'logout', 'login', 'send-code'];
public $optional = ['register', 'logout', 'login', 'send-code', 'test'];
public $mallId;
public function actionTest()
{
return UserPatient::find()->all();
$this->updateDoctor();
$this->updateUser();
$this->updateServInfo();
$this->updatePharmacistInfo();
$this->updateLeadInfo();
$this->updateUserPatient();
$this->updateDoctorPatient();
return ['执行完成'];
}
private function updateDoctor()
{
// 用到了身份证的模型DoctorInfo
$info = DoctorInfo::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->idcard)) {
$v->updated_at = time();
}
$v->save();
}
}
private function updateUser()
{
$info = User::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->idcard)) {
$v->updated_at = time();
}
$v->save();
}
}
private function updateServInfo()
{
$info = ServInfo::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->idcard)) {
$v->updated_at = time();
}
$v->save();
}
}
private function updatePharmacistInfo()
{
$info = PharmacistInfo::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->idcard)) {
$v->updated_at = time();
}
$v->save();
}
}
private function updateLeadInfo()
{
$info = LeadInfo::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->idcard)) {
$v->updated_at = time();
}
$v->save();
}
}
private function updateUserPatient()
{
$info = UserPatient::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->id_card)) {
$v->updated_at = time();
}
$v->save();
}
}
private function updateDoctorPatient()
{
$info = DoctorPatient::find()->all();
foreach ($info as $v) {
if (!is_encrypted($v->id_card)) {
$v->updated_at = time();
}
$v->save();
}
}
public function actionLogin()
{
$post = Yii::$app->request->post();

View File

@@ -8,6 +8,7 @@
namespace admin\foundation;
use common\jobs\LogJob;
use common\services\DataEncryptor;
use Yii;
use yii\base\UserException;
use yii\helpers\Json;
@@ -49,6 +50,10 @@ class JsonResponseFormatter extends \yii\web\JsonResponseFormatter
if (is_array($value)) {
$value = self::aseEncode($value); // 递归处理子数组
} else {
// 数据库中加密的方法需要解密
if (in_array($key, \Yii::$app->params['database_ase_list']) && is_encrypted($value)) {
$value = (new DataEncryptor(Yii::$app->params['ase_key']))->decrypt($value);
}
if (in_array($key, \Yii::$app->params['aseList'])) {
if (is_string($key)) {
$value = ase_encode($value); // 加密指定键值

View File

@@ -34,7 +34,7 @@ return [
'class' => 'yii\redis\Connection',
'hostname' => env('REDIS_HOST'),
'port' => env('REDIS_PORT'),
'password' => env('REDIS_PASSWORD'),
// 'password' => env('REDIS_PASSWORD'),
'database' => 1,
],
// 'cache' => [

View File

@@ -144,6 +144,11 @@ JJvBfLfudYNUjUCyW3gAcOIJ
# 身份证
'id_card',
'idcard',
],
'ase_key' => '3a8f9b2d7c1e4f8a9b2d7c1e4f8a9b2d7c1e4f8a9b2d7c1e4f8a9b2d7c1e4f8a',
'database_ase_list' => [
'id_card',
'idcard',
]
];

View File

@@ -1,6 +1,8 @@
<?php
namespace common\core;
use common\services\DataEncryptor;
use Yii;
use yii\base\Exception;
use yii\db\ActiveRecord;
@@ -15,4 +17,37 @@ class BaseActiveRecord extends ActiveRecord
}
return true;
}
/**
* 新增和编辑数据的时候
* @param $insert
* @throws \Exception
*/
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
// 加密ID卡信息之前检查是否已经加密过
if (!empty($this->idcard) && !is_encrypted($this->idcard)) {
$this->idcard = (new DataEncryptor(\Yii::$app->params['ase_key']))->encrypt($this->idcard);
}
// 加密ID卡信息之前检查是否已经加密过
if (!empty($this->id_card) && !is_encrypted($this->id_card)) {
$this->id_card = (new DataEncryptor(\Yii::$app->params['ase_key']))->encrypt($this->id_card);
}
return true;
}
return false;
}
public function afterFind()
{
parent::afterFind();
// 解密ID卡信息之前检查是否已经是明文
if (!empty($this->id_card) && is_encrypted($this->id_card)) {
$this->id_card = (new DataEncryptor(Yii::$app->params['ase_key']))->decrypt($this->id_card);
}
if (!empty($this->idcard) && is_encrypted($this->idcard)) {
$this->idcard = (new DataEncryptor(Yii::$app->params['ase_key']))->decrypt($this->idcard);
}
}
}

View File

@@ -6,6 +6,7 @@
namespace common\foundation;
use common\services\DataEncryptor;
use Yii;
use yii\helpers\Json;
@@ -132,6 +133,10 @@ class JsonResponseFormatter extends \yii\web\JsonResponseFormatter
if (is_array($value)) {
$value = self::aseEncode($value); // 递归处理子数组
} else {
// 数据库中加密的方法需要解密
if (in_array($key, \Yii::$app->params['database_ase_list']) && is_encrypted($value)) {
$value = (new DataEncryptor(Yii::$app->params['ase_key']))->decrypt($value);
}
if (in_array($key, \Yii::$app->params['aseList'])) {
if (is_string($key)) {
$value = ase_encode($value); // 加密指定键值

View File

@@ -1,6 +1,7 @@
<?php
namespace common\models\oldDb;
use common\services\DataEncryptor;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
@@ -19,6 +20,7 @@ class User extends \common\modelsgii\oldDb\User
];
}
/**
* 可覆盖 fields() 方法来增加、删除、重命名、重定义字段
*/

View File

@@ -0,0 +1,73 @@
<?php
namespace common\services;
use Exception;
class DataEncryptor
{
/**
* @var string 加密方法
*/
private string $cipherMethod = 'AES-256-CBC'; // 加密方法
/**
* @var string 密钥
*/
private string $secretKey; // 密钥
/**
* @var false|int 初始化向量长度
*/
private $ivLength; // 初始化向量长度
/**
* 初始化加密类
* @param $key
*/
public function __construct($key) {
$this->secretKey = hash('sha256', $key, true); // 使用SHA-256哈希生成32字节的密钥
$this->ivLength = openssl_cipher_iv_length($this->cipherMethod);
}
/**
* 加密数据
* @param $data
* @return string
* @throws Exception
*/
public function encrypt($data): string
{
$iv = openssl_random_pseudo_bytes($this->ivLength);
$encryptedData = openssl_encrypt($data, $this->cipherMethod, $this->secretKey, OPENSSL_RAW_DATA, $iv);
if ($encryptedData === false) {
throw new Exception("加密失败" . openssl_error_string());
}
return 'xk_ase_256_'. base64_encode($iv . $encryptedData); // 将初始化向量和加密数据一起返回
}
/**
* 解密数据
* @param $base64EncodedEncryptedData
* @return string
* @throws Exception
*/
public function decrypt($base64EncodedEncryptedData): string
{
if (!is_string($base64EncodedEncryptedData)) return $base64EncodedEncryptedData;
// 替换xk_ase_256_
$base64EncodedEncryptedData = str_replace('xk_ase_256_', '', $base64EncodedEncryptedData);
$decodedData = base64_decode($base64EncodedEncryptedData);
if ($decodedData === false) {
throw new Exception("Base64 decoding failed");
}
$iv = substr($decodedData, 0, $this->ivLength);
$encryptedData = substr($decodedData, $this->ivLength);
$decryptedData = openssl_decrypt($encryptedData, $this->cipherMethod, $this->secretKey, OPENSSL_RAW_DATA, $iv);
if ($decryptedData === false) {
throw new Exception("解密失败" . openssl_error_string());
}
// $pattern = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]|[\x{E000}-\x{F8FF}]/u';
// if (!preg_match($pattern, $str)) return $str;
// ds($decryptedData);
return $decryptedData;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace common\services;
class UtilsService
{
public $urlList = [
'avatar',
'logo',
'url',
'image_url',
];
/**
* @var mixed 单例实例,确保该类只有一个全局实例
*/
private static mixed $_instance;
/**
* 获取实例
* @return null|static
*/
public static function getInstance()
{
$name = get_called_class();
if (!isset(self::$_instance[$name])) {
self::$_instance[$name] = new static();
}
return self::$_instance[$name];
}
/**
* 截取oss链接
* @param $data
* @return mixed
*/
public function truncatedOss($data)
{
foreach ($data as $key => &$value) {
if (in_array($key, $this->urlList)) {
$value = str_replace('http://xiaokang88.oss-cn-hangzhou.aliyuncs.com/', '', $value);
$value = str_replace('https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/', '', $value);
$value = explode('?', $value)[0];
}
}
return $data;
}
}

View File

@@ -13,6 +13,16 @@ if (!function_exists('ds')) {
));
}
}
if (!function_exists('is_encrypted')) {
function is_encrypted($data): bool
{
if (!is_string($data)) {
return false;
}
// 这里应该有逻辑来判断$data是否已经被加密。
return strpos($data, 'xk_ase_256_') === 0;
}
}
if (!function_exists('ase_encode')) {
function ase_encode($data)
{

View File

@@ -9,7 +9,7 @@ $params = array_merge(
return [
'id' => 'app-service',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
// 'bootstrap' => ['log'],
'controllerNamespace' => 'service\controllers',
'modules' => [
'v1' => [

View File

@@ -40,105 +40,116 @@ class DoctorWorkController extends BaseAppController
*/
public function actionInfo()
{
$post= \Yii::$app->request->post();
$store = Store::findOne(\Yii::$app->store);
if(!$store)throw new Exception('门店不存在');
try {
$post= \Yii::$app->request->post();
$store = Store::findOne(\Yii::$app->store);
if(!$store)throw new Exception('门店不存在');
$DoctorInfo= DoctorInfo::find()
->where(['su_id' => \Yii::$app->user->identity->id])
->with(['title', 'hospital','depart','user'])
->one();
$DoctorIdentity= DoctorIdentity::find()
->where(['su_id' => \Yii::$app->user->identity->id])
->one();
$DoctorPracticing= DoctorPracticing::find()
->where(['su_id' => \Yii::$app->user->identity->id])
->one();
if(!$DoctorInfo || !$DoctorIdentity || !$DoctorPracticing){
throw new Exception('医生信息错误');
}
$storeDoctor = StoreDoctor::find()->where([
'su_id' => \Yii::$app->user->identity->getId(),
'store_id' => \Yii::$app->store
])->one();
if(!$storeDoctor)throw new Exception('非该门店医生');
$DoctorInfo= DoctorInfo::find()
->where(['su_id' => \Yii::$app->user->identity->id])
->with(['title', 'hospital','depart','user'])
->one();
$DoctorIdentity= DoctorIdentity::find()
->where(['su_id' => \Yii::$app->user->identity->id])
->one();
$DoctorPracticing= DoctorPracticing::find()
->where(['su_id' => \Yii::$app->user->identity->id])
->one();
if(!$DoctorInfo || !$DoctorIdentity || !$DoctorPracticing){
throw new Exception('医生信息错误');
}
$storeDoctor = StoreDoctor::find()->where([
'su_id' => \Yii::$app->user->identity->getId(),
'store_id' => \Yii::$app->store
])->one();
if(!$storeDoctor)throw new Exception('非该门店医生');
//门店医生小程序码
if(!$storeDoctor->qr_code){
$response = WechatService::getInstance()->app->app_code->getUnlimit('su_id='.\Yii::$app->user->identity->getId().'&store_id='.\Yii::$app->store, [
'page' => 'subPackages/doctor/doctor-detail',
'check_path' => false,
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$path = 'uploads/doctor_code/' . date('Ymd');
$filename = $response->save('uploads/doctor_code/' . date('Ymd'), 'doctor_code_' . $DoctorInfo->su_id.\Yii::$app->store);
$realpath = FuncHelper::getRealFilepath('service', $path . '/' . $filename);
$uploadService = new UploadService();
$url = $uploadService->saveFile($realpath);
$storeDoctor->qr_code = $url;
//门店医生小程序码
if(!$storeDoctor->qr_code){
$response = WechatService::getInstance()->app->app_code->getUnlimit('su_id='.\Yii::$app->user->identity->getId().'&store_id='.\Yii::$app->store, [
'page' => 'subPackages/doctor/doctor-detail',
'check_path' => false,
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$path = 'uploads/doctor_code/' . date('Ymd');
$filename = $response->save('uploads/doctor_code/' . date('Ymd'), 'doctor_code_' . $DoctorInfo->su_id.\Yii::$app->store);
$realpath = FuncHelper::getRealFilepath('service', $path . '/' . $filename);
$uploadService = new UploadService();
$url = $uploadService->saveFile($realpath);
$storeDoctor->qr_code = $url;
$storeDoctor->save();
}
}
//门店医生在线状态
if($storeDoctor->is_online != 1){
StoreDoctor::updateAll(['is_online' => 0],['su_id' => \Yii::$app->user->identity->getId(), 'is_online' => 1]);
$storeDoctor->is_online = 1;
$storeDoctor->last_login_time = time();
$storeDoctor->save();
}
}
//门店医生在线状态
if($storeDoctor->is_online != 1){
StoreDoctor::updateAll(['is_online' => 0],['su_id' => \Yii::$app->user->identity->getId(), 'is_online' => 1]);
$storeDoctor->is_online = 1;
$storeDoctor->last_login_time = time();
$storeDoctor->save();
}
$relates = $DoctorInfo->getRelatedRecords();
$DoctorInfo = $DoctorInfo->toArray();
$DoctorInfo = array_merge($DoctorInfo, $relates);
$wait_accept=Register::find()->where([
'service_user_id'=> \Yii::$app->user->identity->id,
'store_id'=> $post['store_id'],
'status'=>RegisterEnum::WAIT,
'is_pay'=>1,
'is_cancel'=>0,
'is_delete'=>0
])->count();
$relates = $DoctorInfo->getRelatedRecords();
$DoctorInfo = $DoctorInfo->toArray();
$DoctorInfo = array_merge($DoctorInfo, $relates);
$accepting = Register::find()->where([
'service_user_id'=> \Yii::$app->user->identity->id,
'store_id'=> $post['store_id'],
'status'=>RegisterEnum::ACCEPTING,
'is_pay'=>1,
'is_cancel'=>0,
'is_delete'=>0
])->count();
$wait_accept=Register::find()->where([
'service_user_id'=> \Yii::$app->user->identity->id,
'store_id'=> $post['store_id'],
'status'=>RegisterEnum::WAIT,
'is_pay'=>1,
'is_cancel'=>0,
'is_delete'=>0
])->count();
$idcard= DoctorInfo::find()->select(['idcard'])->where(['su_id'=>\Yii::$app->user->id])->one();
$number = substr($idcard['idcard'], strlen($idcard['idcard']) - 2, 1);
$sex=$number % 2 == 0?'女':'男';
$accepting = Register::find()->where([
'service_user_id'=> \Yii::$app->user->identity->id,
'store_id'=> $post['store_id'],
'status'=>RegisterEnum::ACCEPTING,
'is_pay'=>1,
'is_cancel'=>0,
'is_delete'=>0
])->count();
#医生开通的服务
$doctor_service = DoctorService::find()->where(['su_id' => \Yii::$app->user->identity->id])->asArray()->one();
$DoctorInfo['qr_code'] = $storeDoctor->qr_code;
// TODO 这里
$idcard= DoctorInfo::find()->select(['idcard'])->where(['su_id'=>\Yii::$app->user->id])->one();
$number = substr($idcard['idcard'], strlen($idcard['idcard']) - 2, 1);
$sex=$number % 2 == 0?'女':'男';
$ServiceUser=ServiceUser::find()->select(['reason','status'])->where(['id'=>\Yii::$app->user->identity->id])->one();
#医生开通的服务
$doctor_service = DoctorService::find()->where(['su_id' => \Yii::$app->user->identity->id])->asArray()->one();
$DoctorInfo['qr_code'] = $storeDoctor->qr_code;
return [
'store'=>[
'store_id' => $store->id,
'store' => [
'id' => $store->id,
'name' => $store->name,
'see_rate'=>$store->see_rate,
$ServiceUser=ServiceUser::find()->select(['reason','status'])->where(['id'=>\Yii::$app->user->identity->id])->one();
return [
'store'=>[
'store_id' => $store->id,
'store' => [
'id' => $store->id,
'name' => $store->name,
'see_rate'=>$store->see_rate,
]
],
'DoctorInfo'=>$DoctorInfo,
'doctor_service'=>$doctor_service,
'DoctorIdentity'=>$DoctorIdentity,
'DoctorPracticing'=>$DoctorPracticing,
'wait_accept'=>$wait_accept,
'accepting'=>$accepting,
'sex'=>$sex,
'ServiceUser'=>$ServiceUser
];
} catch (\Exception $e) {
return [
'code' => 1,
'msg' => $e->getMessage(),
'data' => [
'line' => $e->getLine(),
]
],
'DoctorInfo'=>$DoctorInfo,
'doctor_service'=>$doctor_service,
'DoctorIdentity'=>$DoctorIdentity,
'DoctorPracticing'=>$DoctorPracticing,
'wait_accept'=>$wait_accept,
'accepting'=>$accepting,
'sex'=>$sex,
'ServiceUser'=>$ServiceUser
];
];
}
}
/**