Laravel怎么开启数据库字段加密 _ Laravel 属性加密Casting方法【教程】

1次阅读

加密字段必须用encrypt casting,其他方式无法自动解密且破坏类型安全;依赖app_key,更换即丢数据;不支持where查询和索引,仅适用于纯存储敏感字段。

Laravel怎么开启数据库字段加密 _ Laravel 属性加密Casting方法【教程】

加密字段必须用 encrypt casting,不能靠模型事件访问器

laravel 的字段加密只在 Eloquent 属性 cast 机制里原生支持,其他方式(比如在 creatingsaving 事件里手动加密)不会自动解密读取,也绕过了框架的类型安全处理。用错地方会导致写入加密、读取明文,或者反过来——读出来一乱码。

实操建议:

  • 在模型中定义 $casts 数组,键为字段名,值为 'encrypt' 字符串
  • 确保该字段数据库类型是 TEXTVARCHAR(足够存 Base64 编码后的密文)
  • 不要对主键、外键、索引字段滥用加密——它们无法被 WHERE 查询直接匹配

示例:

protected $casts = [     'ssn' => 'encrypt',     'api_Token' => 'encrypt' ];

encrypt casting 依赖 Laravel 的 APP_KEY,换密钥等于丢数据

加密/解密全程使用 APP_KEY,不是独立密钥。一旦重置或更换 APP_KEY,所有已加密字段将无法解密,decrypt 会抛出 IlluminateContractsEncryptionDecryptException 错误。

常见错误现象:

  • 本地开发用一个 APP_KEY,上线后用另一个 → 所有加密字段读出来是空或报错
  • 多台服务器没同步 APP_KEY → 部分机器写入、部分机器读不出
  • 误删 .env 后重新 php artisan key:generate → 历史加密数据永久不可恢复

必须提前备份原始 APP_KEY,生产环境严禁随意轮换。

加密字段不支持查询条件(WHERE)、排序(ORDER BY)、索引加速

因为数据以 AES-256-CBC 加密后 Base64 存储,数据库层面看到的是随机字符串,无法做等值比较或范围扫描。试图写 where('ssn', '123-45-6789') 永远查不到结果。

使用场景限制:

  • 只能用于「仅读写、不参与查询逻辑」的敏感字段,如身份证号、银行卡号、密钥本身
  • 如果业务需要按加密字段搜索(例如「找某用户的 token」),得额外建一个非加密的哈希标识字段(如 token_hash),用 hash_hmac('sha256', $token, config('app.key')) 存储
  • mysql 的函数索引、postgresql 的表达式索引对加密字段无效

自定义加密策略要改 AppProvidersAppServiceProvider,不是模型里加方法

默认 encrypt 使用 OpenSSL + APP_KEY,没法换算法或加盐。若需 AES-GCM、带 nonce 的加密,或对接外部 KMS,必须替换 Laravel 的 Encrypter 实现。

实操路径:

  • 写一个实现 IlluminateContractsEncryptionEncrypter 接口的新类
  • AppServiceProvider::register() 中用 $this->app->singleton(Encrypter::class, ...) 替换绑定
  • 注意:所有 Eloquent encrypt casting、encrypt()/decrypt() 辅助函数都会走这个新实例

别在模型里写 setSsnAttribute 手动加密——它和 $casts 不协同,读写行为不一致,调试时容易漏掉一侧。

加密不是开关,是设计决策:字段一旦进 $casts = ['xxx' => 'encrypt'],就等于放弃数据库侧的可检索性、可索引性、可迁移性。很多人卡在“为什么查不到”,其实问题出在一开始就不该把要查的字段加密。

text=ZqhQzanResources