本文目录导读:

在Laravel中加密模型属性有多种方法,我将介绍几种常用的方案:
使用Laravel内置的加密功能
基础方法 - 手动加密/解密
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Crypt;
class User extends Model
{
protected $fillable = ['name', 'email', 'phone', 'address'];
// 手动加密存储
public function setPhoneAttribute($value)
{
$this->attributes['phone'] = Crypt::encryptString($value);
}
// 手动解密读取
public function getPhoneAttribute($value)
{
if ($value) {
return Crypt::decryptString($value);
}
return null;
}
// 加密地址
public function setAddressAttribute($value)
{
$this->attributes['address'] = Crypt::encryptString($value);
}
public function getAddressAttribute($value)
{
if ($value) {
return Crypt::decryptString($value);
}
return null;
}
}
使用Trait进行批量加密
创建一个可复用的Trait:
<?php
namespace App\Traits;
use Illuminate\Support\Facades\Crypt;
trait Encryptable
{
public function getAttribute($key)
{
$value = parent::getAttribute($key);
if (in_array($key, $this->encryptable ?? []) && !empty($value)) {
try {
return Crypt::decryptString($value);
} catch (\Exception $e) {
// 如果是未加密的数据,直接返回
return $value;
}
}
return $value;
}
public function setAttribute($key, $value)
{
if (in_array($key, $this->encryptable ?? []) && !empty($value)) {
$value = Crypt::encryptString($value);
}
return parent::setAttribute($key, $value);
}
}
使用Trait:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\Encryptable;
class User extends Model
{
use Encryptable;
protected $fillable = ['name', 'email', 'phone', 'ssn'];
// 指定需要加密的字段
protected $encryptable = [
'phone',
'ssn',
'bank_account'
];
}
使用第三方包 - spatie/laravel-encryptable
安装包:
composer require spatie/laravel-encryptable
使用方式:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Encryptable\Encryptable;
class User extends Model
{
use Encryptable;
protected $fillable = ['name', 'email', 'token'];
// 指定加密字段
protected $encryptable = [
'token',
'private_key'
];
}
高级用法 - 完整的加密模型示例
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
class Patient extends Model
{
protected $table = 'patients';
protected $fillable = [
'name',
'email',
'phone',
'medical_record',
'insurance_number'
];
// 需要加密的字段配置
protected $encryptable = [
'name' => 'string',
'phone' => 'string',
'medical_record' => 'json',
'insurance_number' => 'string'
];
protected $casts = [
'is_active' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
// 自动处理加密字段
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->encryptFields();
});
static::updating(function ($model) {
$model->encryptFields();
});
}
protected function encryptFields()
{
foreach ($this->encryptable as $field => $type) {
if (isset($this->attributes[$field]) && !empty($this->attributes[$field])) {
$value = $this->attributes[$field];
// 根据类型处理值
if ($type === 'json') {
$value = json_encode($value);
}
// 加密
$this->attributes[$field] = Crypt::encryptString($value);
}
}
}
// 解密单个字段
public function decryptField($field)
{
if (isset($this->attributes[$field]) && in_array($field, array_keys($this->encryptable))) {
try {
$decrypted = Crypt::decryptString($this->attributes[$field]);
if ($this->encryptable[$field] === 'json') {
return json_decode($decrypted, true);
}
return $decrypted;
} catch (\Exception $e) {
// 返回原始值
return $this->attributes[$field];
}
}
return null;
}
// 获取解密后的所有字段
public function getDecryptedAttributes()
{
$data = [];
foreach ($this->encryptable as $field => $type) {
$data[$field] = $this->decryptField($field);
}
return $data;
}
// 重写toArray方法
public function toArray()
{
$attributes = parent::toArray();
foreach ($this->encryptable as $field => $type) {
if (isset($attributes[$field])) {
$attributes[$field] = $this->decryptField($field);
}
}
return $attributes;
}
}
// 使用示例
$patient = Patient::create([
'name' => '张三',
'phone' => '13800138000',
'medical_record' => ['诊断', '药物', '过敏史'],
'insurance_number' => 'ABC123456'
]);
// 读取自动解密
echo $patient->name; // 张三(自动解密)
echo $patient->phone; // 13800138000
// 获取解密后的JSON字段
$medical = $patient->decryptField('medical_record');
print_r($medical);
// 获取所有解密字段
$allData = $patient->getDecryptedAttributes();
注意事项和建议
搜索加密字段
// 数据库无法直接搜索加密字段,需要特殊处理
public static function searchByEncryptedField($field, $value)
{
$records = self::all();
return $records->filter(function ($record) use ($field, $value) {
try {
return $record->decryptField($field) === $value;
} catch (\Exception $e) {
return false;
}
});
}
索引和性能考虑
// 为搜索创建单独的明文索引字段
protected $fillable = [
'email', // 明文存储用于索引
'email_hash', // 存储哈希值用于精确查找
'phone_encrypted' // 加密存储
];
public function setPhoneAttribute($value)
{
$this->attributes['phone_encrypted'] = Crypt::encryptString($value);
$this->attributes['phone_hash'] = hash('sha256', $value);
}
public function findByPhone($phone)
{
return self::where('phone_hash', hash('sha256', $phone))->first();
}
批量数据处理
// 批量加密现有数据
public static function encryptExistingRecords()
{
self::chunk(100, function ($records) {
foreach ($records as $record) {
foreach ((new static)->encryptable as $field => $type) {
if (!empty($record->attributes[$field])) {
$record->{$field} = $record->attributes[$field];
$record->save();
}
}
}
});
}
这些方法各有优劣,建议根据项目需求选择合适的方式,如果需要简单的加密功能,直接使用Laravel自带的Crypt即可;如果项目中有多个模型需要加密,建议使用Trait或第三方包的形式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播