數據庫主鍵通常是有序自增主鍵,極易被爬蟲抓取數據,做爲應用開發者,這是不該該的,你辛辛苦苦收集的數據轉眼之間被其餘人給抓取了,是否是很大的損失?php
generate short unique ids from integers
理解爲數字編碼庫便可,幾乎支持市面上全部語言。node
available in JavaScript, Ruby, Python, Java, Scala, PHP, Perl, Perl 6, Swift, Clojure, Objective-C, C, C++11, D, F#, Go, Erlang, Lua, Haskell, OCaml, Elixir, Rust, Smalltalk, ColdFusion, Groovy, Kotlin, Nim, VBA, Haxe, Crystal, Elm, ActionScript, CoffeeScript, Bash, R, TSQL, PostgreSQL and for
$hashids = new Hashids\Hashids('this is my salt'); $id = $hashids->encode(1, 2, 3); $numbers = $hashids->decode($id);
該庫並非一個加密庫,因此不建議用來加密敏感數據,咱們的數據庫主鍵ID並非業務上的敏感數據,因此這個不要緊。web
因爲該編解碼是獨立與業務以外的,因此須要處理的地方在下面:數據庫
這兩個步驟不該該提如今控制器中,控制器拿到的數據是解碼好的,響應的數據是原始數據,而後咱們在響應中處理。編程
class HashidsHelper { public static function encode($id) { $hashids = new \Hashids\Hashids('salt',16); return $hashids->encode($id); } public static function decode($hash) { $hashids = new \Hashids\Hashids('salt',16); $data= $hashids->decode($hash); return empty($data)?null:$data; } public static function decodeArray(array $hashes) { return array_map([HashidsHelper::class, 'decode'], $hashes); } /** * 遞歸編碼 * @param array $data */ public static function encodeRecursive(array &$data) { foreach ($data as $key => &$value) { if (is_array($value)) { self::encodeRecursive($value); continue; } if (strpos($key, 'id') !== false && is_numeric($value)) { $data[$key] = static::encode($value); } } } /** * 遞歸解碼 * @param array $data */ public static function decodeRecursive(array &$data) { foreach ($data as $key => &$value) { if (is_array($value)) { self::decodeRecursive($value); continue; } if (strpos($key, 'id') !== false) { if (is_string($value)) { $id = static::decode($value); $data[$key] = $id ?? $value; } elseif (is_array($value)) { $data[$key] = static::decodeArray($value); } } } } }
1.新建JsonParser繼承Yii自帶的JsonParser,代碼以下json
class JsonParser extends \yii\web\JsonParser { /** * @inheritDoc */ public function parse($rawBody, $contentType) { $data = parent::parse($rawBody, $contentType); if ($data !== null) { HashidsHelper::decodeRecursive($data); } return $data; } }
2.新建Request集成Yii自帶的Request,重寫getQueryParams,代碼以下:cookie
public function getQueryParams() { $data = parent::getQueryParams(); if ($data !== null) { HashidsHelper::decodeRecursive($data); } return $data; }
3.配置web.php的components,更改成咱們自定義的處理器app
'request' => [ 'class' => \app\components\Request::class, // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 'cookieValidationKey' => '123456', 'enableCsrfValidation' => false, 'parsers' => [ 'application/json' => \app\components\web\JsonParser::class ] ],
1.新建JsonResponseFormatter繼承Yii的JsonResponseFormatter,代碼以下:yii
class JsonResponseFormatter extends \yii\web\JsonResponseFormatter { /** * @inheritDoc */ public function format($response) { if ($response->data !== null) { HashidsHelper::encodeRecursive($response->data); } parent::format($response); } }
2.配置web.php的components,替換response組件post
'response' => [ 'class' => \app\components\web\Response::class, 'format' => Response::FORMAT_JSON, 'formatters' => [ 'json' => [ 'class' => \app\components\web\JsonResponseFormatter::class, 'prettyPrint' => YII_DEBUG ] ] ],
1.SiteController添加方法
public function actionA($corporation_id) { $data = Yii::$app->request->post(); var_dump($data, $corporation_id); } public function actionB() { return [ 'app_id' => 1, 'app' => [ 'app_id' => 2 ] ]; }
2.請求測試,這個加密過的hash讀者可能解不開,由於咱們用的salt不同,替換爲你本身的便可
POST /site/a?corporation_id=XaYeAV2q80pkB4KL { "corporation_id": "XaYeAV2q80pkB4KL", "applet":{ "id":"XaYeAV2q80pkB4KL", "appid":"xxxxxx" } }
3.響應的內容以下:
array(2) { ["corporation_id"]=> int(1) ["applet"]=> array(2) { ["id"]=> int(1) ["appid"]=> string(6) "xxxxxx" } } int(1)
4.響應測試
GET /site/b
5.響應內容以下
{ "app_id": "XaYeAV2q80pkB4KL", "app": { "app_id": "LOnMp3QR5lryDgRK" } }
不知道這個算不算AOP編程?我的以爲算,在業務邏輯以外處理,業務層對外部輸入和自身輸出是透明的(理解爲業務層本身不知道加解密
)。
本文核心在於兩個遞歸方法,其餘語言相似,像nodejs可使用中間件來處理。