API 鉴权新姿势 - 签名鉴权
laravel-api-auth
laravel API 鉴权
这是一个 laravel 的 API 鉴权包, laravel-api-auth
采用密钥加密的鉴权方式,只要客户端不被反编译从而泄露密钥,该鉴权方式理论上来说是安全的。
项目地址: github.com/96qbhy/laravel-api-auth
求star
!
安装
composer require 96qbhy/laravel-api-auth
配置
-
注册
ServiceProvider
:Qbhy\LaravelApiAuth\ServiceProvider::class,
laravel 5.5+ 版本不需要手动注册
-
发布配置文件
php artisan vendor:publish --provider="Qbhy\LaravelApiAuth\ServiceProvider"
-
在
App\Http\Kernal
中注册中间件protected $routeMiddleware = [ 'api_auth' => Qbhy\LaravelApiAuth\LaravelApiAuthMiddleware::class, // other ... ];
-
添加
role
php artisan api_auth
然后按照格式把
access_key
和secret_key
添加到,config/api_auth.php
里面的roles
数组中。'roles' => [ '{access_key}' => [ 'name' => '{role_name}', // 角色名字,例如 android 'secret_key' => '{secret_key}', ], ],
-
自定义签名方法 (可选)
config/api_auth.php
中的encrypting
可以修改为自定义的签名函数,该函数将传入三个参数: 密钥:$secret_key
、随机字符串:$echostr
、时间戳:$timestamp
,返回签名后的字符串。该函数默认为:/** * @param $secret_key * @param $echostr * @param $timestamp * @return string */ function encrypting($secret_key, $echostr, $timestamp) { return md5($secret_key . $echostr . $timestamp); }
-
自定义签名校验规则(可选)
config/api_auth.php
中的rule
可以修改为自定义的校验函数,该函数将传入三个参数: 密钥:$secret_key
、客户端签名:$signature
、服务端签名:$server_signature
,必须返回布尔值。该函数默认为:/** * @param $secret_key * @param $signature * @param $server_signature * @return bool */ function rule($secret_key, $signature, $server_signature) { return $signature === $server_signature; }
-
自定义错误处理(可选)
config/api_auth.php
中的error_handler
可以修改为自定义的错误处理函数,该函数将传入两个参数: 请求:$request
、错误码:$code
。该函数默认为:/** * @param Request $request * @param int $code * @return \Illuminate\Http\JsonResponse */ function error_handler($request, $code) { return response()->json([ 'msg' => 'Forbidden', 'code' => $code ], 403); }
$code
可能是以下几个值中的一个:LaravelApiAuthMiddleware::LACK_HEADER
-> 缺少请求头。LaravelApiAuthMiddleware::ACCESS_KEY_ERROR
->access_key
错误。LaravelApiAuthMiddleware::SIGNATURE_ERROR
-> 签名错误。LaravelApiAuthMiddleware::SIGNATURE_LAPSE
-> 签名失效,客户端签名时间和服务端签名时间差超过设置的timeout
值。LaravelApiAuthMiddleware::SIGNATURE_REPETITION
-> 签名重复,规定时间内出现两次或以上相同的签名。
使用
路由中
Route::get('api/example', function(Request $request){
// $request->get('client_role');
// todo...
})->middleware(['api_auth']);
\\ or
Route::group(['middleware'=>'api_auth'], function(){
// routes...
});
通过验证后
$request
会添加一个client_role
字段,该字段为客户端的角色名称。
前端
import axios from 'axios';
const access_key = '{access_key}'; // 服务端生成的 access_key
const secret_key = '{secret_key}'; // 服务端生成的 secret_key
const timestamp = Date.parse(new Date()) / 1000; // 取时间戳
const echostr = 'asldjaksdjlkjgqpojg64131321'; // 随机字符串自行生成
function encrypting(secret_key, echostr, timestamp){
return md5(secret_key + echostr + timestamp); // md5 库自行引入
}
const requestConfig = {
headers: {
"api-signature": encrypting(secret_key, echostr, timestamp),
"api-echostr": echostr,
"api-timestamp": timestamp,
"api-access-key": access_key
}
};
axios.post('/api/example',{},requestConfig).then(res=>{
// todo
});
本例子为
web
前端的例子,其他客户端同理,生成签名并且带上指定参数即可正常请求。
通过自定义签名方法和自定义校验方法,可以使用其他加密方法进行签名,例如哈希
等其他加密算法。更多自定义可以直接复制Qbhy\LaravelApiAuth\LaravelApiAuthMiddleware
中间件后自行修改 。有问题请开issue
。
96qbhy.com
96qbhy@gmail.com
本作品采用《CC 协议》,转载必须注明作者和本文链接
自己顶一个。
然而大多数情况反编译客户端的成本很低
网页web端应该是明文啊~~ 这个key ~~不等于直接知道了么
@leo ios 不考虑,安卓端加了盐 + 混淆加密啥的,反编译难度其实没有想象中的那么简单。而且,密钥这种东西可以编译成
.so
后缀的动态库,即使反编译了APP,也不用担心密钥泄露的,这种加密方法,即使知道了加密算法,没有密钥,也没有用的。@依剑听雨 所以 web 端的 API 通常都比较简单,加密方式也不适用这种密钥方式,还有就是 web 端的 API 通常要跟 APP 的
API 区分开来,像是
微信网页版
的 API 能做的事情就非常有局限性,正是因为 web 端没有绝对安全(或者说相对安全)的 API 鉴权方法。另外这个叫“签名”比叫“加密”合适
@leo 谢谢建议,之前我也在纠结呢。
顶一顶
laravel5后直接用自带passport做接口,如果允许的话再配合Spatie或者Bouncer权限包扩展下,鉴权挺方便的,不过你的方法快捷,之前做个和你差不多的,不过是走在request类上面,如下:
例如在控制器需要用到则判断
$request->check_sign('密钥')
即可,中间件也一样。@ab0029 嗯,方法差不多。中间统一处理错误比较方便一点。
@ab0029 http_build_query 有个问题,如果其中一项为 null 会丢失掉
http_build_query(['a'=>null,'b'=>1,'c'=>false]);//b=1&c=0
不过这里 Request 取的应该都成字符串了
顶顶更健康
@96qbhy 这样的签名防止不了篡改请求参数
@jake_zou 这个是为了防止没有权限的调用接口做的,防止篡改参数还是建议 https 或者 jwt。
谁才是原创
https://laravelacademy.org/post/7964.html
@BigPark 我也在laravel学院发过,并且允许学院君转载了。看内容就知道作者是我啊。
由于时间原因,此项目已不建议大家使用了。如果有类似需求的可以评论区讨论。
作者 这个包现在还能使用吗?
没有做判空和字段的合法性检测,不知道是不需要还是...
用不了了