所以我的数据库中有实体的字段
class Person
{
// other fields
/**
* @var string
*
* @ORM\Column(name="last_name", type="string", length=50, nullable=false)
*/
private $lastName;
/**
* @var string
*
* @ORM\Column(name="first_name", type="string", length=50, nullable=false)
*/
private $firstName;
// getters and setters
}
我有一个名为 SecureEncryptor 的服务。它具有 Decrypt() 和 Encrypt() 函数 - 基本上你只需将加密/未加密(分别)字符串传递给它,它就会执行相应的操作。
问题是我不确定如何将该服务与实体结合使用 - 特别是在考虑表单(类型)时。我的意思是我知道我可以只获取该字段并调用 Decrypt 函数,但这不适用于绑定(bind)到 Person 实体的类型。
我开始为解密的人制作一个单独的实体,然后我会在处理数据库时切换它,但这似乎是错误的。我的另一个想法是从实体调用服务,但我也读过这也是错误的。
有任何想法吗?
编辑:
这基本上就是我想要做的:
$builder->get('dateOfBirth')
->addModelTransformer(new CallbackTransformer(
function ($encryptedDOB) {
return $this->encryptor->decrypt($encryptedDOB, salt); // How do I get the salt value here?
},
function ($decryptedDOB) {
return $this->encryptor->encrypt($decryptedDOB, salt); // How do I get the salt value here?
}
));
或者可能在此步骤之前解密/加密数据,但不确定如何完成。
编辑 2:
我找到了 this这表明您可以在 PRE_SET_DATA 事件中获取实体数据,但您无法在其中添加数据转换器,因此不确定它是如何工作的。
最佳答案
经过三天的困惑 - 可能是 20 多个小时的挫折之后,我终于找到了正确的方法来做到这一点。 Entity Event Listeners
所以我做了以下改动
app\config\services.yaml
parameters:
...
encryption_key: '%kernel.project_dir%/path/to/my/key'
services:
...
App\EventListeners\PatientListener:
arguments: [@session]
tags:
- { name: doctrine.event_listener, event: prePersist }
- { name: doctrine.event_listener, event: preUpdate }
- { name: doctrine.event_listener, event: postLoad }
然后我做了服务
<?php
namespace App\EventListeners;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use App\Entity\Patients;
use ParagonIE\Halite\HiddenString;
use ParagonIE\Halite\KeyFactory;
use ParagonIE\Halite\Symmetric\Crypto as Symmetric;
use ParagonIE\Halite\Symmetric\EncryptionKey;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Session\Session;
class PatientListener
{
private $params;
private $session;
private $logger;
public function __construct(ParameterBagInterface $params,
Session $session, LoggerInterface $logger)
{
$this->params = $params;
$this->session = $session;
$this->logger = $logger;
}
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
if ($entity instanceof Patients)
{
$this->encryptFields($entity);
}
}
public function preUpdate(LifecycleEventArgs $args)
{
$entity = $args->getObject();
if ($entity instanceof Patients)
{
$this->encryptFields($entity);
}
}
public function postLoad(LifecycleEventArgs $args)
{
$entity = $args->getObject();
if ($entity instanceof Patients)
{
$this->decryptFields($entity);
}
}
private function loadKey() : EncryptionKey
{
try
{
KeyFactory::loadEncryptionKey($this->params->get('encryption_key'));
}
catch(\Throwable $e)
{
$this->session->getFlashBag()->add('danger', 'Unable to load encryption key!');
$this->logger->emergency(
'Unable to lod the encryption key!', array(
'error' => $e->getMessage(),
));
throw;
}
}
private function encryptFields(Patients $patient)
{
$key = $this->loadKey();
// Encrypt the variables
$lastName = $this->encrypt('Last Name', $patient->getLastName(), $key);
// Set the entity variables
$patient->setLastName($lastName);
return $patient;
}
private function encrypt($fieldName, $value, $key)
{
try {
return Symmetric::encrypt(
new HiddenString($value),
$key
);
} catch(\Throwable $e)
{
$this->session->getFlashBag()->add('danger', 'Unable to encrypt field');
$this->logger->critical(
'Unable to encrypt field "'.$fieldName.'" in Patients entity. DB update terminated.', array(
'error' => $e->getMessage(),
));
throw;
}
}
private function decryptFields(Patients $patient)
{
$key = $this->loadKey();
$id = $patient->getId();
// Decrypt the variables
$lastName = $this->decrypt($id, 'Last Name', $patient->getLastName(), $key);
// Set the entity variables
$patient->setLastName($lastName);
}
private function decrypt($id, $fieldName, $value, $key)
{
try
{
return Symmetric::decrypt($value, $key);
}
catch (\Throwable $e)
{
$this->session->getFlashBag()->add('warning', 'Unable to decrypt field');
$this->logger->warning(
'Unable to decrypt field "'.$fieldName.'" in Patients entity for ID: '.$id, array(
'error' => $e->getMessage(),
));
}
}
}
现在数据在加载到数据库时被加密,在加载到实体时被解密。
这种方式是正确的,因为以任何其他方式执行此操作(自定义原则类型、数据转换器、在 Controller 中执行等)总是有可能如果其他人制作另一种形式或在另一个 Controller 中使用该实体,它可能会离开数据解密(又名非常糟糕)。这种方式可确保数据始终通过原则正确加密和解密(除非您执行一些自定义 DQL\SQL,在这种情况下,您可能需要根据自己的操作自行处理)。
关于php - Symfony 4 - 使用服务加密/解密理论中使用的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52617635/