├── .gitignore ├── README.md ├── composer.json ├── config └── hyid.php ├── example.php └── src ├── Base64UrlSafeEncoder.php ├── Exceptions └── HyidException.php ├── Hyid.php ├── HyidAble.php ├── ServiceProvider.php └── helper.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | .idea 3 | composer.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hyid 2 | hide your id. 隐藏你的ID. 3 | 4 | ## 使用场景 5 | 当我们的应用需要提供一个无状态通过ID获取信息的接口,例如 `GET /user/{id}` ,此类接口只要递增ID进行请求,就可以得到我们数据库中所有公开信息,这很显然不是我们想看到的。 6 | `hyid` 可以帮助你隐藏我们不希望用户看到的ID字段,或者其他数字字段。 7 | 8 | ## 安装 9 | `composer require 96qbhy/hyid` 10 | 11 | ### laravel or lumen 12 | 1. 注册服务提供者 : `Qbhy\Hyid\ServiceProvider::class` 13 | 2. 发布配置文件(lumen可以自行复制 `config/hyid.php` 或者安装 `vendor:publish` 命令): `php artisan vendor:publish --provider=Qbhy\Hyid\ServiceProvider` 14 | 15 | 16 | ## 使用 17 | ### 配置 18 | ```text 19 | HYID_SECRET=qbhy 20 | HYID_OFFSET=1996 21 | HYID_RANDOM_LENGTH=6 22 | ``` 23 | > HYID_RANDOM_LENGTH 值建议不超过 6 24 | ### 代码示例 25 | ```php 26 | class User extends Model{ 27 | use Qbhy\Hyid\HyidAble; 28 | 29 | // or 30 | public function getUserId($userId){ 31 | return hyid($userId); 32 | } 33 | 34 | // or 35 | public function toArray(){ 36 | $data = parent::toArray(); 37 | 38 | $data['id'] = hyid()->encode($data['id']); 39 | 40 | return $data; 41 | } 42 | } 43 | // decode 44 | ``` 45 | #### 解码后得到原始的ID 46 | ```php 47 | public function userinfo($id){ 48 | return User::query()->findOrFail(hyid()->decode($id))->toArray(); 49 | } 50 | ``` 51 | > UserController 52 | 53 | #### 非 laravel 或者 lumen 环境下使用 54 | ```php 55 | // 非 laravel or lumen 下,可以自行实例化 Hyid 类 56 | $secret = 'qbhy'; 57 | $offset = 1996; 58 | $hyid = new Hyid($secret,$offset,4); 59 | 60 | $encodedId = $hyid->encode(1); 61 | $id = $hyid->decode($encodedId); // 1 62 | ``` 63 | 64 | 96qbhy@gmail.com 65 | [qbhy/hyid](https://github.com/qbhy/hyid) 66 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "96qbhy/hyid", 3 | "description": "hidden your id", 4 | "authors": [ 5 | { 6 | "name": "96qbhy", 7 | "email": "96qbhy@gmail.com" 8 | } 9 | ], 10 | "require": {}, 11 | "autoload": { 12 | "psr-4": { 13 | "Qbhy\\Hyid\\": "src" 14 | } 15 | }, 16 | "require-dev": { 17 | "laravel/lumen-framework": "5.5" 18 | }, 19 | "extra": { 20 | "laravel": { 21 | "providers": [ 22 | "Qbhy\\Hyid\\ServiceProvider" 23 | ] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /config/hyid.php: -------------------------------------------------------------------------------- 1 | env('HYID_SECRET'), 10 | 'offset' => env('HYID_OFFSET'), 11 | 'randomLength' => env('HYID_RANDOM_LENGTH', 4), 12 | ]; -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | encode(10086)); 16 | var_dump($id = $hyid->decode($encoded)); 17 | } catch (\Qbhy\Hyid\Exceptions\HyidException $exception) { 18 | var_dump($encoder->decode($encoded)); 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/Base64UrlSafeEncoder.php: -------------------------------------------------------------------------------- 1 | secret = $secret; 46 | $this->offset = $offset; 47 | $this->randomLength = $randomLength; 48 | $this->encoder = new Base64UrlSafeEncoder(); 49 | } 50 | 51 | /** 52 | * @param int $id 53 | * @param string $prefix 54 | * 55 | * @return string 56 | * @throws \Exception 57 | */ 58 | public function encode($id, string $prefix = '') 59 | { 60 | $offsetId = $id + $this->offset; 61 | $rand = $this->randInt(); 62 | $signatureString = $prefix . $rand . $offsetId; 63 | $signature = $this->signature($signatureString); 64 | $header = substr($signature, $this->offset % 2, strlen($rand . $offsetId)); 65 | 66 | return $this->encoder->encode($header . Hyid::SPREAD . $signatureString); 67 | } 68 | 69 | public function randInt(): int 70 | { 71 | $n = ''; 72 | $i = $this->randomLength; 73 | while ($i--) { 74 | $n .= random_int(1, 9); 75 | } 76 | 77 | return intval($n); 78 | } 79 | 80 | /** 81 | * @param string $encodedId 82 | * @param string $prefix 83 | * 84 | * @return int 85 | * @throws HyidException 86 | */ 87 | public function decode(string $encodedId, string $prefix = '') 88 | { 89 | $raw = $this->encoder->decode($encodedId); 90 | 91 | $attrs = explode(Hyid::SPREAD, $raw); 92 | 93 | if (count($attrs) !== 2) { 94 | throw new HyidException('hyid exception!'); 95 | } 96 | 97 | list($header, $signatureString) = $attrs; 98 | 99 | $offsetId = substr($signatureString, strlen($prefix) + $this->randomLength); 100 | 101 | $this->checkHeader($header, $signatureString, strlen($offsetId)); 102 | 103 | return $offsetId - $this->offset; 104 | } 105 | 106 | protected function signature($signatureString) 107 | { 108 | return hash_hmac('SHA256', $signatureString, $this->secret); 109 | } 110 | 111 | protected function checkHeader($header, $signatureString, $offsetLen) 112 | { 113 | $signature = $this->signature($signatureString); 114 | if ($header !== substr($signature, $this->offset % 2, $this->randomLength + $offsetLen)) { 115 | throw new HyidException('hyid header exception'); 116 | } 117 | } 118 | 119 | /** 120 | * @return Base64UrlSafeEncoder 121 | */ 122 | public function getEncoder(): Base64UrlSafeEncoder 123 | { 124 | return $this->encoder; 125 | } 126 | 127 | /** 128 | * @return int 129 | */ 130 | public function getOffset(): int 131 | { 132 | return $this->offset; 133 | } 134 | } -------------------------------------------------------------------------------- /src/HyidAble.php: -------------------------------------------------------------------------------- 1 | attributes['id']); 23 | } 24 | 25 | public function rawId() 26 | { 27 | return $this->attributes['id']; 28 | } 29 | } -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 20 | $this->publishes([ 21 | $configSource => base_path('config/hyid.php') 22 | ]); 23 | } 24 | 25 | if ($this->app instanceof Application) { 26 | $this->app->configure('hyid'); 27 | } 28 | 29 | $this->mergeConfigFrom($configSource, 'hyid'); 30 | } 31 | 32 | public function register() 33 | { 34 | $this->setupConfig(); 35 | 36 | $this->app->singleton(Hyid::class, function () { 37 | return new Hyid(config('hyid.secret'), config('hyid.offset'), config('hyid.randomLength', 4)); 38 | }); 39 | 40 | $this->app->alias(Hyid::class, 'hyid'); 41 | } 42 | } -------------------------------------------------------------------------------- /src/helper.php: -------------------------------------------------------------------------------- 1 | encode((int) $id); 26 | } 27 | } 28 | 29 | --------------------------------------------------------------------------------