github:https://github.com/doukoi-BDB
今日主题:
1、laravel firebase/php-jwt token验证
2、预计阅读 10 分钟,正文 3700 字。
这里会分成几个阶段说明,让大家可以用极简的内容看懂 所谓的 jwt 签名验证。
一、说明
二、使用
阶段一【说明】:
jwt 英文全称(json web token),主要一般用于api 的跨域安全验证。
阶段二【使用】:
可以直接composer 拉取一个第三方 jwt库,官方也有demo!!!
代码语言:javascript复制官方地址:
https://github.com/firebase/php-jwt
安装命令:
composer require firebase/php-jwt
接下来就是具体代码,结合官方案例代码进行基础封装:
代码语言:javascript复制//生成token
public function createToken(){
$publicKey = 'xxx'; //唯一标识,也可以用业务中的唯一标识值
$time = time();
$token = [
'iat' => $time, //签发时间
'nbf' => $time, //(Not Before):某个时间点后才能访问,比如设置time 30,表示当前时间30秒后才能使用
'exp' => $time 7200, //过期时间,这里设置2个小时
'data' => [ //自定义信息
'public_id' => 'xxx'
]
];
$token = JWT::encode($token, $publicKey,'HS256'); //签发token
$data = [
'error'=>0,
'mgs'=>'success',
'data'=>['token'=>$token]];
return json_encode($data);
}
//使用&刷新token
public function verifyToken($token)
{
$publicKey = 'xxxx'; //key要和签发的时候一样,唯一标识
try {
JWT::$leeway = 60;//当前时间减去60,把时间留点余地,同步其他服务器时间,解决nbf字段验证不通过问题
$decoded = JWT::decode($token, $publicKey, ['HS256']); //HS256方式,这里要和签发的时候对应
$arr = (array)$decoded;
print_r($arr);
} catch(FirebaseJWTSignatureInvalidException $e) { //签名不正确
echo $e->getMessage();
}catch(FirebaseJWTBeforeValidException $e) { // 签名在某个时间点之后才能用
echo $e->getMessage();
}catch(FirebaseJWTExpiredException $e) { // token过期
echo $e->getMessage();
}catch(Exception $e) { //其他错误
echo $e->getMessage();
}
}
顺便这里用laravel 作为基础,给大家说下通用方法怎么搞!!!
可以定义一个中间件,通过中间件自动验证token:
代码语言:javascript复制注意:
php artisan make:middleware VerifySign //生成中间件
//VerifySign:验证token
<?php
namespace AppHttpMiddleware;
use Closure;
use Exception;
use FirebaseJWTJWT;
class VerifySign
{
/**
* Handle an incoming request.
*
* @param IlluminateHttpRequest $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$result = ['error'=>0,'msg'=>'','data'=>[]];
$key = $request->header('key');
$token = $request->header('token');
if(empty($key) || empty($token)){
$result['error'] = 403;
$result['msg'] = 'headers param error';
Log::error('app api headers param error:key='.$key.', token='.$token);
return response()->json($result);
}
try {
JWT::$leeway = 60;//当前时间减去60,把时间留点余地
if(!$rs = JWT::decode($token, $key, ['HS256'])){//HS256方式,这里要和签发的时候对应
$result['error'] = 403;
$result['msg'] = 'validation failure';
Log::error('app api validation failure:key='.$key.', token='.$token);
return response()->json($result);
}
} catch(FirebaseJWTSignatureInvalidException $e) { //签名不正确
$error = $e->getMessage();
}catch(FirebaseJWTBeforeValidException $e) { // 签名在某个时间点之后才能用
$error = $e->getMessage();
}catch(FirebaseJWTExpiredException $e) { // token过期
$error = $e->getMessage();
}catch(Exception $e) { //其他错误
$error = $e->getMessage();
}
if(!empty($error)){
$result['error'] = 403;
$result['msg'] = $error;
Log::error('app api error:'.$error);
return response()->json($result);
}
return $next($request);
}
}
app/Http/Kernel.php 应用的路由中间件列表,app.sign中间件中的路由请求接口时都需要携带key和token 。
代码语言:javascript复制protected $routeMiddleware = [
//...
'app.sign' => AppHttpMiddlewareVerifySign::class,
];
定义路由routes/web.php
代码语言:javascript复制Route::get('auth/token', 'UserController@createToken');//获取token
//需要通过验证token的路由
Route::group(['namespace' => 'App','middleware' => ['app.sign']], function () {
Route::get('/auth/refresh/token', 'UserController@refreshToken');//刷新token
});
控制器调用
代码语言:javascript复制//获取token
public function getToken(Request $request)
{
return $this->biz->createToken($request->all());
}
请求结果
代码语言:javascript复制请求生成token:
http://xx.com/web/auth/token?xxx=11111 (参数组装上面自由发挥)
{
"error": 0,
"msg": "ok",
"data": {
"key": "eyJpdiI6InloN1NNc3R5aVdzWE9WZjdoYzFFXC9nPT0iLCJ2YWx1ZSI6ImxSTE1YOXJ0bllDMERseEFiaWc0a1E9PSIsIm1hYyI6IjM5ZjAzM2U0OWNhNzY1NjRkNzY1N2RjZmQwYmNlMDYwNWMzZjM0MDJkNTRlODg3OWI3NGE5MmY2MzA2YmFjYTQifQ==",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NjQ3OTgyNjksIm5iZiI6MTU2NDc5ODI2OSwiZXhwIjoxNTY0ODA1NDY5fQ.T8e4eCBfU6AeZ5RpRLPGTgd5MaY5asyglfV7s-1A57M",
"expire": 7200
}
}