Laravel 对 ID 进行对称加密的 Composer 包 hashid
GitHub:
jiaxincui/hashid
介绍
一个对Laravel应用模型ID进行对称加密的辅助函数。
只适用于正整数加密。
安装
$ composer require jiaxincui/hashid
配置
- 复制
config/hashid.php
文件到Laravel项目的config
文件夹。 - 在.env文件添加配置项
HASH_ID_ALPHABET=your-key
。- 为了Hash成更安全的字符串,请手动重新生成
HASH_ID_ALPHABET
,为0-9a-zA-Z共62个字符随机排序,字符不可重复,长度为16-62,可使用以下方法生成echo str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
简单使用
包含两个辅助方法
id_encode()
和id_decode()
。
在Laravel项目的任何地方均可使用这两个函数对ID进行加密或解密。
- 为了Hash成更安全的字符串,请手动重新生成
例子
echo id_encode(4568); //输出:N5lkv0
echo id_decode('N5lkvO'); //输出:4568
//不可对float类型数字加密,不可对负数加密,给定任何非正整数参数都会抛出错误,如:
echo id_encode(2.36); //非正整数,抛出错误
echo id_encode(-23); //非正整数,抛出错误
//解密时任何无效字符串参数或校验错误都会抛出错误, 如:
echo id_decode('m_Dl9'); //包含无效字符,抛出错误
echo id_decode('nlK8GhRW'); //校验错误,抛出错误
和hashids/hashids不同的是hashids
提供多个数字或包含多个数字的数组加密成一个字符串,
解密时以数组形式返回,这在实际应用中并不常见,反而给使用带来一定麻烦,
而此包对此进行了一些处理,不提供多个数字或多个数字数组的加密,解密时直接返回解密后的数字。
Laravel深度应用
加密
有2种方法实现自动加密
-
如果模型主键为
id
通过Hashid提供的trait,在数据库模型中使用
use Hashid;
,对结果中的id
字段自动加密成字符串,例如:<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use Jiaxincui\Hashid\Traits\Hashid;
class User extends Model
{
use Hashid;
}
* 如果模型中的主键不是`id`
你需要在模型中定义一个访问器,如你的主键为`pid`,在Model中添加访问器如下:
```php
public function getPidAttribute($value)
{
return id_encode($value);
}
解密
通过Hashid提供的middleware对路由参数解码,在控制器中无需做任何操作即可解码加密后的路由参数。
首先在App\Http\Kernel.php
中注册中间件,在Kernel
类的$routeMiddleware
属性添加中间件条目。例如:
'hashid' => \Jiaxincui\Hashid\Http\Middleware\Hashid::class,
现在你可以在路由中分配中间件了。例如:
Route::resource('/users', 'UserController')->middleware('hashid');
中间件参数
默认情况下,Hashid
中间件会解密当前路由的所有路由参数,如果你想指定被解密的路由参数可在中间件传入参数,例如:
Route::get('users/{user}/posts/{post}/comments/{comment}', function ($user, $post, $comment) {
//
})->middleware('hashid:user,post');
以上例子中间件只解密给出的参数,如以上例子会解密路由参数user
和post
,不会解密commnent
现在你的应用已经具备完整的加密和解密模型ID的功能。
本作品采用《CC 协议》,转载必须注明作者和本文链接
感谢分享。
github 上已经 有轮子 了,结合自己实际体验,觉着可以做一个 middleware,因为往往在数据库操作的时候需要原始 ID。
这个不错,一般电商之类的比较在意这个,因为会泄漏订单数量什么的。
@yansongda 啊,真的有呀,花了几个小时重复造了个轮子。
你那个项目删了?打不开了。我自己搞的 int2string 估计跟你的差不多,也有几个现成的轮子:
@yansongda 也提到了,数据库操作时不方便,我现在是定义了 route model 。准备抽空写个专门处理 hashid 的轮子,管理各种 hashid ,以及零成本给 model 配置 hashid 。一直没腾出时间,也没找到现有的轮子..
@ElfSundae 重新提交了项目已更新文章,看到了你说的两个轮子,思路大致相同,使用时确实有些不方便,暂时想到的是读取时可在model里利用访问器加密id,像这样
操作数据库还需要这样
@yansongda的思路是在操作数据库时候能否使用middleware,暂时还没好的方案
middleware 一般是针对 request 和 response 的,@yansongda 的意思可能是解析 URL 中的 hashid 然后 decode
@ElfSundae 确实想到了一些思路,在middleware里确实可以获取到路由参数
以前用 Golang 写过一个 Base62 编码的,应该类似。
http://www.cnblogs.com/qufo/p/5730229.html
@ElfSundae 现在1.1.0发布,可以深度应用了,加密trait和解密middleware添加,感谢@ElfSundae @yansongda 提供思路
这个不错,如果可以确认生成的加密字符串不会重复的话,其实可以替代uuid了。
@jenkincei 你定义了
getIdAttribute
但不一定所有主键都叫id
, 参考 Model 的getKey()
和getRouteKey()
@ElfSundae 谢谢提醒,这个动态添加访问器实现起来过于复杂,暂时没有想到更好的办法,如果主键不是id只能手动添加访问器了。
有一个思路,在 trait 里重载
getAttribute
, 大概意思如下: