Laravel 对 ID 进行对称加密的 Composer 包 hashid

GitHub:
jiaxincui/hashid

介绍

一个对Laravel应用模型ID进行对称加密的辅助函数。

依赖于hashids/hashids

只适用于正整数加密。

安装

$ composer require jiaxincui/hashid

配置

  1. 复制config/hashid.php文件到Laravel项目的config文件夹。
  2. 在.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进行加密或解密。

例子


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');

以上例子中间件只解密给出的参数,如以上例子会解密路由参数userpost,不会解密commnent

现在你的应用已经具备完整的加密和解密模型ID的功能。

本作品采用《CC 协议》,转载必须注明作者和本文链接
jenkincei
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 14

感谢分享。

github 上已经 有轮子 了,结合自己实际体验,觉着可以做一个 middleware,因为往往在数据库操作的时候需要原始 ID。

6年前 评论

这个不错,一般电商之类的比较在意这个,因为会泄漏订单数量什么的。

6年前 评论
jenkincei

@yansongda 啊,真的有呀,花了几个小时重复造了个轮子。

6年前 评论

你那个项目删了?打不开了。我自己搞的 int2string 估计跟你的差不多,也有几个现成的轮子:

@yansongda 也提到了,数据库操作时不方便,我现在是定义了 route model 。准备抽空写个专门处理 hashid 的轮子,管理各种 hashid ,以及零成本给 model 配置 hashid 。一直没腾出时间,也没找到现有的轮子..

6年前 评论
jenkincei

@ElfSundae 重新提交了项目已更新文章,看到了你说的两个轮子,思路大致相同,使用时确实有些不方便,暂时想到的是读取时可在model里利用访问器加密id,像这样

public function getIdAttribute($value)
    {
        return id_encode($value);
    }

操作数据库还需要这样

public function show($id)
    {
        $id = id_decode($id));
    }

@yansongda的思路是在操作数据库时候能否使用middleware,暂时还没好的方案

6年前 评论

middleware 一般是针对 request 和 response 的,@yansongda 的意思可能是解析 URL 中的 hashid 然后 decode

6年前 评论
jenkincei

@ElfSundae 确实想到了一些思路,在middleware里确实可以获取到路由参数

$router = Route::current(); //获取当前路由实例
$id = id_decode($router->parameter('id')); //获取当前路由实例id参数并解密
$router->setParameter('id', $id); //设置当前路由的参数id为解密后的数字
6年前 评论

以前用 Golang 写过一个 Base62 编码的,应该类似。

http://www.cnblogs.com/qufo/p/5730229.html

6年前 评论
jenkincei

@ElfSundae 现在1.1.0发布,可以深度应用了,加密trait和解密middleware添加,感谢@ElfSundae @yansongda 提供思路

6年前 评论
Jourdon

这个不错,如果可以确认生成的加密字符串不会重复的话,其实可以替代uuid了。

6年前 评论

@jenkincei 你定义了 getIdAttribute 但不一定所有主键都叫 id , 参考 Model 的 getKey()getRouteKey()

6年前 评论
jenkincei

@ElfSundae 谢谢提醒,这个动态添加访问器实现起来过于复杂,暂时没有想到更好的办法,如果主键不是id只能手动添加访问器了。

6年前 评论

有一个思路,在 trait 里重载 getAttribute , 大概意思如下:

public function getAttribute($key)
{
    $value = parent::getAttribute($key);

    if ($value && $key === $this->getRouteKeyName()) {
        $value = decode($value);
    }

    return $value;
}
6年前 评论
if (! is_null($value) && $key == ...)
6年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!