Api通讯数据的加解密

第一章 背景

在与 APP 的 api 通讯中,经常会将敏感数据进行加密传输,然后再解密进行处理。在项目开发的时候,也会封装方法去对数据进行加解密。接下来我们通过php的laravel框架来实现加解密,下面是我通过 middlewareResponse::macro 实现加解密的方案。

第二章 请求的解密

对请求数据进行处理,首选当然是在 middleware 中进行。

  namespace App\Http\Middleware;

    use Closure;
    use Illuminate\Contracts\Encryption\DecryptException;
    use Illuminate\Contracts\Encryption\Encrypter;
    use Illuminate\Http\Request;
    use Symfony\Component\HttpFoundation\ParameterBag;

    class DecryptApiRequest{
        /**
         * @var Encrypter
         */
        protected $encrypter;

        public function __construct(Encrypter $encrypter){
            $this->encrypter = $encrypter;
        }

        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next){
            try {
                $content = $this->decrypt($request->getContent());
            } catch (DecryptException $exception) {
                return abort(403);
            }

            return $next($this->putIn($request, $content));
        }

        /**
         * decrypt the content
         * @param string $content
         * @return string
         */
        protected function decrypt(string $content){
            return $this->encrypter->decrypt($content, false);
        }

        /**
         * put the decrypt data into request
         * @param Request $request
         * @param string $content
         * @return Request
         */
        protected function putIn(Request $request, string $content){
            if ($request->getContentType() === 'json') {
                $request->setJson(new ParameterBag((array) json_decode($content, true)));
            } else {
                $request->attributes = new ParameterBag([$request->getContentType() => $content]);
            }

            return $request;
        }
    }

该中间件中添加了 decrypt()putIn() 方法,其中 decrypt() 用于处理数据的解密,putIn() 用于将解密后的数据放入 Request 对象用,供后面访问使用。由于加密数据请求一般是采用文本的形式在 body 中进行发送,所以这里在获取到解密的数据之后,根据 contentType 类型存入了 Request 对象中,如果是 json 则存入了 Requestjson 属性中, 如果是其他类型,则以 contentType 为键 content 为值的形式存入了 attributes 中。

于是乎,解密完成了,并且也不会遗弃 Request 对象,不会因为在 Reqeust 中取不到解密后的数据而放弃他。

怎么获取数据?

json 类型直接使用 Request::get($key);
text 类型使用 Request::get('txt');
其他类型,Reqeust::getContentType() 看看就知道了。

第三章 响应的加密

这里用的是响应宏进行了处理。具体请看响应的文档 【响应宏】
代码如下:

namespace App\Providers;

use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;

class ResponseMacroServiceProvider extends ServiceProvider{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot(){
        Response::macro('encrypt', function ($value) {
            if (is_array($value)) $value = json_encode($value);
            if ($value instanceof Jsonable) $value = $value->toJson();
            return Response::make(app()->make(Encrypter::class)
                ->encrypt((string) $value, false));
        });
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register(){
        //
    }
}

在加密数据之前,首先对数据类型进行了处理,最终会将数据转化为 string 类型进行加密。
使用时,直接调用 encrypt() 方法即可。

Route::post('/', function (\Illuminate\Http\Request $request) {
    return response()->encrypt(['a', 'b']);
});
posted @ 2019-05-06 01:02  南山道士  阅读(87)  评论(0编辑  收藏  举报