Api通讯数据的加解密
第一章 背景
在与 APP 的 api 通讯中,经常会将敏感数据进行加密传输,然后再解密进行处理。在项目开发的时候,也会封装方法去对数据进行加解密。接下来我们通过php的laravel框架来实现加解密,下面是我通过 middleware
和 Response::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
则存入了 Request
的 json
属性中, 如果是其他类型,则以 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']);
});